Flutter: persistent bottom navigation rebuilds sub-page on tab change

Viewed 242

I am using the persistent_bottom_nav_bar package and have implemented it as outlined in their Readme. Please refer to the main.dart code below.

The issue: On page1, I can navigate in to a sub-page that contains a ListView. When on that sub-page, if I don't pop that page but just directly tap on the bottom navigation items to change page, that ListView on the the sub-page continues to rebuild for every tab that I navigate to. Not sure how to prevent that from happening??

In my actual implementation (the below is a simplified code), this sub-page is a stateful widget. I therefore tried to extend the stateful widget with AutomaticKeepAliveClientMixin to not rebuild the page, but that didn't help. In the example I've given here, the sub-page is in fact a stateless widget and the issue still happens. So I suspect it stems from the package itself and not whether the page is stateful or stateless.

Anyone who might have any ideas of what's going on? Thanks in advance.

main.dart

import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';

import 'page1.dart';
import 'page2.dart';
import 'page3.dart';
import 'page4.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo',
      home: HomeScaffold(),
    );
  }
}

class HomeScaffold extends StatefulWidget {

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

class _HomeScaffoldState extends State<HomeScaffold> {
  PersistentTabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PersistentTabController(initialIndex: 0);
  }

  List<Widget> _buildScreens() {
    return [
      Page1(),
      Page2(),
      Page3(),
      Page4(),
    ];
  }

  List<PersistentBottomNavBarItem> _navBarsItems() {
    return [
      _buildBottomNavBarItem('Page 1', Icons.home),
      _buildBottomNavBarItem('Page 2', Icons.search),
      _buildBottomNavBarItem('Page 3', Icons.message),
      _buildBottomNavBarItem('Page 4', Icons.settings),
    ];
  }

  @override
  Widget build(BuildContext context) {

    return PersistentTabView(
      context,
      controller: _controller,
      screens: _buildScreens(),
      items: _navBarsItems(),
      confineInSafeArea: true,
      backgroundColor: Colors.white,
      handleAndroidBackButtonPress: true, 
      resizeToAvoidBottomInset: true, 
      stateManagement: true, 
      // hideNavigationBar: true, 
      hideNavigationBarWhenKeyboardShows: true, 
      decoration: NavBarDecoration(
        borderRadius: BorderRadius.circular(5.0),
        colorBehindNavBar: Colors.white,
      ),
      popAllScreensOnTapOfSelectedTab: true,
      popActionScreens: PopActionScreensType.all,
      itemAnimationProperties: ItemAnimationProperties( 
        duration: Duration(milliseconds: 200),
        curve: Curves.ease,
      ),
      screenTransitionAnimation: ScreenTransitionAnimation( 
        animateTabTransition: true,
        curve: Curves.ease,
        duration: Duration(milliseconds: 200),
      ),
      navBarStyle: NavBarStyle.style8, 
    );

  }
}

PersistentBottomNavBarItem _buildBottomNavBarItem(String title, IconData icon) {
  return PersistentBottomNavBarItem(
    icon: Icon(icon),
    title: title,
    activeColorPrimary: Colors.indigo,
    inactiveColorPrimary: Colors.grey,
  );
}

page1.dart

import 'page1_sub_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class Page1 extends StatefulWidget {
  @override
  _Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    print('Building Page1');
    super.build(context);

    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Center(child: Text('Page1')),
          SizedBox(height: 40),
          RaisedButton(
            onPressed: () => Navigator.of(context).push(
              CupertinoPageRoute(builder: (BuildContext context) => Page1SubPage()),
            ),
            child: Text('Sub-page'),
          ),
        ],
      ),
    );
  }
}

page1_sub_page.dart

import 'package:flutter/material.dart';

class Page1SubPage extends StatelessWidget {
  // Generate dummy list
  final List dummyList = List.generate(100, (index) {
    return {
      "id": index,
      "title": "This is the tile $index",
    };
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            child: ListView.builder(
              itemCount: dummyList.length,
              itemBuilder: (context, index) {
                print('Building tile $index');
                return Card(
                  elevation: 6,
                  margin: EdgeInsets.all(10),
                  child: ListTile(
                    leading: CircleAvatar(
                      child: Text(dummyList[index]["id"].toString()),
                      backgroundColor: Colors.purple,
                    ),
                    title: Text(dummyList[index]["title"]),
                  ),
                );
              } ,
            )));
  }
}
0 Answers
Related