演示效果

通常搭建一个主框架大概是这个样子
Kapture 2020-06-21 at 22.41.41.gif

上代码

主页代码

整体是 IndexedStack + BottomNavigationBar 的大结构

  1. class MainPage extends StatefulWidget {
  2. MainPage({Key key}) : super(key: key);
  3. @override
  4. _MainPageState createState() => _MainPageState();
  5. }
  6. class _MainPageState extends State<MainPage> {
  7. /// 当前索引
  8. int _currentIndex = 0;
  9. @override
  10. Widget build(BuildContext context) {
  11. //这里打印了主页
  12. debugPrint('MainPage');
  13. return Scaffold(
  14. body: IndexedStack(
  15. index: _currentIndex,
  16. children: <Widget>[
  17. HomePage(),//首页
  18. FindPage(),//发现
  19. MsgPage(),//消息
  20. UserPage(),//我的
  21. ],
  22. ),
  23. bottomNavigationBar: BottomNavigationBar(
  24. type: BottomNavigationBarType.fixed,
  25. selectedItemColor: Theme.of(context).primaryColor,
  26. unselectedItemColor: Colors.grey,
  27. showUnselectedLabels: true,
  28. currentIndex: _currentIndex,
  29. onTap: (newIndex) {
  30. if (_currentIndex != newIndex) {
  31. setState(() {
  32. _currentIndex = newIndex;
  33. });
  34. }
  35. },
  36. items: [
  37. BottomNavigationBarItem(
  38. icon: Icon(Icons.home),
  39. title: Text('首页'),
  40. ),
  41. BottomNavigationBarItem(
  42. icon: Icon(Icons.explore),
  43. title: Text('发现'),
  44. ),
  45. BottomNavigationBarItem(
  46. icon: Icon(Icons.email),
  47. title: Text('消息'),
  48. ),
  49. BottomNavigationBarItem(
  50. icon: Icon(Icons.people),
  51. title: Text('我的'),
  52. )
  53. ]),
  54. );
  55. }
  56. }

Tab 页面代码

IndexedStack 中对应的四个页面布局如下

  1. /// 首页
  2. class HomePage extends StatefulWidget {
  3. @override
  4. _HomePageState createState() => _HomePageState();
  5. }
  6. class _HomePageState extends State<HomePage> {
  7. @override
  8. Widget build(BuildContext context) {
  9. debugPrint('HomePage');
  10. return Scaffold(
  11. appBar: AppBar(title: Text('首页'),),
  12. body: Center(child: Text('首页')),
  13. );
  14. }
  15. }
  16. /// 发现
  17. class FindPage extends StatefulWidget {
  18. @override
  19. _FindPageState createState() => _FindPageState();
  20. }
  21. class _FindPageState extends State<FindPage> {
  22. @override
  23. Widget build(BuildContext context) {
  24. debugPrint('FindPage');
  25. return Scaffold(
  26. appBar: AppBar(title: Text('发现'),),
  27. body: Center(child: Text('发现')),
  28. );
  29. }
  30. }
  31. /// 消息
  32. class MsgPage extends StatefulWidget {
  33. @override
  34. _MsgPageState createState() => _MsgPageState();
  35. }
  36. class _MsgPageState extends State<MsgPage> {
  37. @override
  38. Widget build(BuildContext context) {
  39. debugPrint('MsgPage');
  40. return Scaffold(
  41. appBar: AppBar(title: Text('消息'),),
  42. body: Center(child: Text('消息')),
  43. );
  44. }
  45. }
  46. ///我的
  47. class UserPage extends StatefulWidget {
  48. @override
  49. _UserPageState createState() => _UserPageState();
  50. }
  51. class _UserPageState extends State<UserPage> {
  52. @override
  53. Widget build(BuildContext context) {
  54. debugPrint('UserPage');
  55. return Scaffold(
  56. appBar: AppBar(title: Text('我的'),),
  57. body: Center(child: Text('我的')),
  58. );
  59. }
  60. }

发现问题

看上面的代码似乎很合理,但是当我们点击【发现】 Tab 时,5 个页面都进行了 rebuild,log 日志如下
image.pngimage.png
是不是有些诧异?但是仔细分析主页代码,因为点击切换 Tab 时,执行了setState({}) 那么主页必然会 rebuild,然后 4 个Tab 页面又是在 IndexedStack 中创建的,所以 4 个 Tab 页,也一起 rebuild 了

  1. return Scaffold(
  2. body: IndexedStack(
  3. index: _currentIndex,
  4. children: <Widget>[
  5. HomePage(),//首页
  6. FindPage(),//发现
  7. MsgPage(),//消息
  8. UserPage(),//我的
  9. ],
  10. ),
  11. bottomNavigationBar: BottomNavigationBar(
  12. ...
  13. onTap: (newIndex) {
  14. if (_currentIndex != newIndex) {
  15. setState(() {
  16. _currentIndex = newIndex;
  17. });
  18. }
  19. },
  20. items: [
  21. ...
  22. ]),
  23. );

那么怎么解决这个问题呢?

解决问题

我们把 4 个 Tab 页面放到 initState 中即可

  1. class MainPage extends StatefulWidget {
  2. MainPage({Key key}) : super(key: key);
  3. @override
  4. _MainPageState createState() => _MainPageState();
  5. }
  6. class _MainPageState extends State<MainPage> {
  7. /// 当前索引
  8. int _currentIndex = 0;
  9. /// 页面列表
  10. List pageList;
  11. @override
  12. void initState() {
  13. ///初始化 4 个 Page
  14. pageList = <Widget>[
  15. HomePage(), //首页
  16. FindPage(), //发现
  17. MsgPage(), //消息
  18. UserPage(), //我的
  19. ];
  20. super.initState();
  21. }
  22. @override
  23. Widget build(BuildContext context) {
  24. debugPrint('MainPage');
  25. return Scaffold(
  26. body: IndexedStack(
  27. index: _currentIndex,
  28. children: pageList,
  29. ),
  30. bottomNavigationBar: BottomNavigationBar(
  31. type: BottomNavigationBarType.fixed,
  32. selectedItemColor: Theme.of(context).primaryColor,
  33. unselectedItemColor: Colors.grey,
  34. showUnselectedLabels: true,
  35. currentIndex: _currentIndex,
  36. onTap: (newIndex) {
  37. if (_currentIndex != newIndex) {
  38. setState(() {
  39. _currentIndex = newIndex;
  40. });
  41. }
  42. },
  43. items: [
  44. BottomNavigationBarItem(
  45. icon: Icon(Icons.home),
  46. title: Text('首页'),
  47. ),
  48. BottomNavigationBarItem(
  49. icon: Icon(Icons.explore),
  50. title: Text('发现'),
  51. ),
  52. BottomNavigationBarItem(
  53. icon: Icon(Icons.email),
  54. title: Text('消息'),
  55. ),
  56. BottomNavigationBarItem(
  57. icon: Icon(Icons.people),
  58. title: Text('我的'),
  59. )
  60. ]),
  61. );
  62. }
  63. }

最终点击 Tab 页看看效果
image.png