Flutter onboarding

When it comes to user onboarding in mobile apps, creating a smooth and engaging experience is crucial. One way to do this in Flutter is by building an onboarding screen that guides users through your app’s key features. In this tutorial, we’ll walk through the process of creating an onboarding screen in Flutter.

Getting Started

Step 1: Set Up Assets

Add necessary assets

Step 2: Create an Onboarding page

import 'package:flutter/material.dart';

class OnboardingPageModel {
  final String title;
  final String description;
  final String image;
  final Color bgColor;
  final Color textColor;

  OnboardingPageModel(
      {required this.title,
      required this.description,
      required this.image,
      this.bgColor = Colors.blue,
      this.textColor = Colors.white});
}

class OnboardingPage extends StatefulWidget {
  final List<OnboardingPageModel> pages;

  const OnboardingPage({Key? key, required this.pages}) : super(key: key);

  @override
  _OnboardingPageState createState() => _OnboardingPageState();
}

class _OnboardingPageState extends State<OnboardingPage> {
  // Store the currently visible page
  int _currentPage = 0;
  // Define a controller for the pageview
  final PageController _pageController = PageController(initialPage: 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: AnimatedContainer(
        duration: const Duration(milliseconds: 250),
        color: widget.pages[_currentPage].bgColor,
        child: SafeArea(
          child: Column(
            children: [
              Expanded(
                // Pageview to render each page
                child: PageView.builder(
                  controller: _pageController,
                  itemCount: widget.pages.length,
                  onPageChanged: (idx) {
                    // Change current page when pageview changes
                    setState(() {
                      _currentPage = idx;
                    });
                  },
                  itemBuilder: (context, idx) {
                    final _item = widget.pages[idx];
                    return Column(
                      children: [
                        Expanded(
                          flex: 3,
                          child: Padding(
                            padding: const EdgeInsets.all(32.0),
                            child: Image.asset(
                              _item.image,
                            ),
                          ),
                        ),
                        Expanded(
                            flex: 1,
                            child: Column(children: [
                              Padding(
                                padding: const EdgeInsets.all(16.0),
                                child: Text(_item.title,
                                    style: Theme.of(context)
                                        .textTheme
                                        .headline6
                                        ?.copyWith(
                                          fontWeight: FontWeight.bold,
                                          color: _item.textColor,
                                        )),
                              ),
                              Container(
                                constraints: BoxConstraints(maxWidth: 280),
                                padding: const EdgeInsets.symmetric(
                                    horizontal: 24.0, vertical: 8.0),
                                child: Text(_item.description,
                                    textAlign: TextAlign.center,
                                    style: Theme.of(context)
                                        .textTheme
                                        .bodyText2
                                        ?.copyWith(
                                          color: _item.textColor,
                                        )),
                              )
                            ]))
                      ],
                    );
                  },
                ),
              ),

              // Current page indicator
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: widget.pages
                    .map((item) => AnimatedContainer(
                          duration: const Duration(milliseconds: 250),
                          width: _currentPage == widget.pages.indexOf(item)
                              ? 20
                              : 4,
                          height: 4,
                          margin: const EdgeInsets.all(2.0),
                          decoration: BoxDecoration(
                              color: Colors.white,
                              borderRadius: BorderRadius.circular(10.0)),
                        ))
                    .toList(),
              ),

              // Bottom buttons
              SizedBox(
                height: 100,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    TextButton(
                        onPressed: () {
                          // Handle Skipping onboarding page
                        },
                        child: Text(
                          "Skip",
                          style: TextStyle(color: Colors.white),
                        )),
                    TextButton(
                      onPressed: () {
                        if (_currentPage == widget.pages.length - 1) {
                          // This is the last page
                        } else {
                          _pageController.animateToPage(_currentPage + 1,
                              curve: Curves.easeInOutCubic,
                              duration: const Duration(milliseconds: 250));
                        }
                      },
                      child: Text(
                        _currentPage == widget.pages.length - 1
                            ? "Finish"
                            : "Next",
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

PageView.builder is a widget that creates a scrollable view of pages, and it uses a builder function to create each page dynamically based on the index.

itemCount is set to the total number of onboarding pages, which is derived from homeCon.demoData.length.

scrollDirection: Axis.horizontal specifies that the pages should be scrollable horizontally.

onPageChanged is a callback function that is called when the user changes the page. It updates the current page index in the homeCon.currentPage variable, presumably for keeping track of the active page.

itemBuilder is a function that generates each onboarding page based on the current index. Inside the builder function, each page is represented as a Column containing various widgets.

SizedBox with a height of 50 pixels creates space at the top of each page.

SvgPicture.asset displays an SVG image specified by homeCon.demoData[index].image.

Spacer() is used to push the content to the bottom of each page, so that other elements, like the dot indicators and buttons, can be placed below the onboarding content.

Overall, this code is responsible for creating a dynamic onboarding screen with pages that include SVG images, titles, and descriptions. The onPageChanged callback updates the current page index as the user swipes through the pages, allowing for seamless navigation.

import 'package:flutter/material.dart';

enum WeatherTypeEnum {
  Thunderstorm,
  Drizzle,
  Rain,
  Snow,
  Clear,
  Clouds,
  other,
}

extension WeatherTypeEnumExtension on String? {
  WeatherTypeEnum? toWeatherType() {
    WeatherTypeEnum? value;
    switch (this) {
      case 'Thunderstorm':
        value = WeatherTypeEnum.Thunderstorm;
        break;
      case 'Drizzle':
        value = WeatherTypeEnum.Drizzle;
        break;
      case 'Snow':
        value = WeatherTypeEnum.Snow;
        break;
      case 'Rain':
        value = WeatherTypeEnum.Rain;
        break;
      case 'Clear':
        value = WeatherTypeEnum.Clear;
        break;
      case 'Clouds':
        value = WeatherTypeEnum.Clouds;
        break;
      default:
        value = WeatherTypeEnum.other;
        break;
    }
    return value;
  }
}

extension WeatherTypeEnumThemeExtension on WeatherTypeEnum? {
  WeatherThemeEntity? toWeatherTheme() {
    WeatherThemeEntity? value;
    switch (this) {
      case WeatherTypeEnum.Thunderstorm:
      case WeatherTypeEnum.Clouds:
      case WeatherTypeEnum.Rain:
        value = WeatherThemeEntity(
          firstColor: blue3E97C8,
          secondColor: blue3E97C8.withOpacity(0.8),
        );
        break;
      case WeatherTypeEnum.Drizzle:
      case WeatherTypeEnum.Snow:
        value = WeatherThemeEntity(
          firstColor: blue3E97C8,
          secondColor: blueD8E7F2,
        );
        break;
      case WeatherTypeEnum.Clear:
        value = WeatherThemeEntity(
          firstColor: Colors.orange,
          secondColor: Colors.yellow,
        );
        break;
      case WeatherTypeEnum.other:
        value = WeatherThemeEntity(
          firstColor: greyDDDDDD,
          secondColor: black404040,
        );
        break;
      default:
        value = WeatherThemeEntity(
          firstColor: blue3E97C8,
          secondColor: blueD8E7F2,
        );
        break;
    }
    return value;
  }
}
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x