Tela de introdução/integração do aplicativo Flutter com carrossel e pontos animados – NO Package
Você aprenderá a criar uma página de integração como a mostrada abaixo em seu aplicativo Flutter.
Como você pode ver, os indicadores são animados – é incrível que sejam necessárias apenas 10 linhas de código!
Conteudo
Começar
Vamos começar com OnboardingPage, que é um StatefulWidget. Além disso, defina uma variável chamada _selectedIndex e defina seu valor padrão como 0.
class OnboardingPage extends StatefulWidget { const OnboardingPage({super.key}); @override State<OnboardingPage> createState() => _OnboardingPageState(); } class _OnboardingPageState extends State<OnboardingPage> { int _selctedIndex = 0; @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( children: [ // TODO: Onboard Content // TODO: Animated Dots // TODO: Button ], ), ), ); } } List<Map<String, dynamic>> demoData = [ { "illustration": "assets/Illustrations/Illustrations_1.svg", "title": "All your favorites", "text": "Order from the best local restaurants \nwith easy, on-demand delivery.", }, { "illustration": "assets/Illustrations/Illustrations_2.svg", "title": "Free delivery offers", "text": "Free delivery for new customers via Apple Pay\nand others payment methods.", }, { "illustration": "assets/Illustrations/Illustrations_3.svg", "title": "Choose your food", "text": "Easily find your type of food craving and\nyou’ll get delivery in wide range.", }, ];
Onboard Content
No OnboardContent
, começamos com uma ilustração. Em seguida, há um título, que tornamos maior ao definir seu estilo como titleLarge
. Por fim, há uma breve descrição. É por isso que temos três parâmetros: illustration
, title
, e text
.
class OnboardContent extends StatelessWidget { const OnboardContent({ super.key, required this.illustration, required this.title, required this.text, }); final String illustration, title, text; @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: AspectRatio( aspectRatio: 1, child: SvgPicture.asset(illustration), ), ), const SizedBox(height: 16), Text( title, style: Theme.of(context) .textTheme .titleLarge! .copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( text, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ], ); } }
Agora, vamos colocar o OnboardContent
em ação em nossa página de integração. Se você observar a visualização, verá que os usuários podem deslizar para a esquerda ou para a direita. Para isso, usamos um PageView
. Quando uma página é alterada, atualizamos o _selectedIndex
. Isso será útil mais tarde, quando adicionarmos pontos animados para indicar a posição da página. Substitua TODO: Onboard Content
pelo código abaixo
const Spacer(flex: 2), SizedBox( height: 500, child: PageView.builder( itemCount: demoData.length, onPageChanged: (value) { setState(() { _selctedIndex = value; }); }, itemBuilder: (context, index) { return OnboardContent( illustration: demoData[index]['illustration'], title: demoData[index]['title'], text: demoData[index]['text'], ); }, ), ), const Spacer(),
Animated dots
Ao criar pontos animados, optamos por animações implícitas porque elas são diretas e simples, eliminando a necessidade de controladores ou configurações complexas. Só precisamos definir a duração. O AnimatedContainer é um deles. Aqui, se o ponto estiver ativo, sua largura se expandirá para 24; caso contrário, permanecerá em 6. A transição de 24 para 6 não acontece instantaneamente; ela ocorre gradualmente durante o período de tempo especificado na duração.
lass AnimatedDot extends StatelessWidget { const AnimatedDot({ super.key, required this.isActive, }); final bool isActive; @override Widget build(BuildContext context) { return AnimatedContainer( duration: const Duration(milliseconds: 300), height: 6, width: isActive ? 20 : 6, decoration: BoxDecoration( color: isActive ? primaryColor : const Color(0xFF868686).withOpacity(0.25), borderRadius: const BorderRadius.all(Radius.circular(12)), ), ); } }
Agora, para exibir os pontos em nossa página, basta substituir o TODO
: Animated Dots
pelo código abaixo
Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( demoData.length, (index) => Padding( padding: const EdgeInsets.only(right: 6), child: AnimatedDot(isActive: _selctedIndex == index), ), ), ), const Spacer(flex: 2),
Button
Estamos quase lá! O único componente que falta concluir é o botão. Vamos finalizar isso substituindo TODO
: Button pelo código abaixo
ElevatedButton( onPressed: () {}, child: Text( "Get Started".toUpperCase(), ), ), const Spacer(),