Flutter PageView Example With Dots Indicator

Flutter PageView is great for sliding with animation. We will also show how to use indicator. There are a few things we must do

  1. declare a PageController
  2. declare List of Pages
  3. keep track of active page
  4. use PageView.builder
  5. call animateToPage

PageController

We need to declare a PageController like below so that we may use the instance inside PageView.builder and also for dots indicator.

final PageController _pageController = PageController(initialPage: 0);

_pageController we will use inside PageView.builder and for calling animateToPage()

List of screens

Next we will declare a list pages or screen to show on the screen. These screens would be slidable. We would be able to slide them left or right direction. You may use as many pages as you want.

  final List<Widget> _pages = [
    const PageOne(),
    const PageTwo(),
    const PageThree()
  ];

We will access each of the page using _pages and index of the PageView.builder widget.  One of the example of this page or screen is

class PageOne extends StatelessWidget {
  const PageOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      color: Colors.pink,
      child: const Text(
        'Page view',
        style: TextStyle(fontSize: 30, color: Colors.white),
      ),
    );
  }
}

Active page

We declare _activePage variable to keep track of the current page or screen. _activePage initial value is 0 and it gets update as we slide or tap.

 // the index of the current page
  int _activePage = 0;

PageView.builder()

Next the most important part is PageView.builder() widget. Inside this we would be using all the above variables we declared.

PageView.builder(
            controller: _pageController,
            onPageChanged: (int page) {
              setState(() {
                _activePage = page;
              });
            },
            itemCount: _pages.length,
            itemBuilder: (BuildContext context, int index) {
              return _pages[index % _pages.length];
            },
          )

Look carefully controller, onPageChanged, itemCount and itemBuilder. The setState() inside onPageChanged callback helps to update the active page index.

PageView.builder() is just like any other builder widget in Flutter. The above code should go inside the body property of Scaffold. You should put PageView.builder inside Stack() widget rather than Column() widget.

Dots indicator

Let's see how to work on the dots indicator without a plugin. If you use PageView.builder() widget, it's easy to implement dots indicator.

Because we will have access to _pages and _pageController variables inside the body property of Scaffold, we would be able to find the right index, and using that index and animateToPage(), we will just to a new page.

List<Widget>.generate(
                    _pages.length,
                        (index) => Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 10),
                      child: InkWell(
                        onTap: () {
                          _pageController.animateToPage(index,
                              duration: const Duration(milliseconds: 300),
                              curve: Curves.easeIn);
                        },
                        child: CircleAvatar(
                          radius: 8,
                          backgroundColor: _activePage == index
                              ? Colors.amber
                              : Colors.grey,
                        ),
                      ),
                    ))

Inside List.generate() we used _pages and _pageController. _pageController has a helpful method name animateToPage(), this function helps us to do the animation if you use inside onTap().

Complete code

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      // remove the debug banner
        debugShowCheckedModeBanner: false,
        home: PageViewDemo());
  }
}

// Construct Dots Indicator

class PageViewDemo extends StatefulWidget {
  const PageViewDemo({Key? key}) : super(key: key);

  @override
  State<PageViewDemo> createState() => _PageViewDemoState();
}

class _PageViewDemoState extends State<PageViewDemo> {
  // declare and initizlize the page controller
  final PageController _pageController = PageController(initialPage: 0);

  // the index of the current page
  int _activePage = 0;

  final List<Widget> _pages = [
    const PageOne(),
    const PageTwo(),
    const PageThree()
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          PageView.builder(
            controller: _pageController,
            onPageChanged: (int page) {
              setState(() {
                _activePage = page;
              });
            },
            itemCount: _pages.length,
            itemBuilder: (BuildContext context, int index) {
              return _pages[index % _pages.length];
            },
          ),

          Positioned(
            bottom: 0,
            left: 0,
            right: 0,
            height: 100,
            child: Container(
              color: Colors.black54,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List<Widget>.generate(
                    _pages.length,
                        (index) => Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 10),
                      child: InkWell(
                        onTap: () {
                          _pageController.animateToPage(index,
                              duration: const Duration(milliseconds: 300),
                              curve: Curves.easeIn);
                        },
                        child: CircleAvatar(
                          radius: 8,
                          backgroundColor: _activePage == index
                              ? Colors.amber
                              : Colors.grey,
                        ),
                      ),
                    )),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

PageView advanced animation

Recent posts