Tela de introdução/integração do aplicativo Flutter com carrossel e pontos animados – NO Package

Tempo de leitura: 3 minutes

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!

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: illustrationtitle, 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(),