演示效果
通常搭建一个主框架大概是这个样子
上代码
主页代码
整体是 IndexedStack + BottomNavigationBar 的大结构
class MainPage extends StatefulWidget {
MainPage({Key key}) : super(key: key);
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
/// 当前索引
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
//这里打印了主页
debugPrint('MainPage');
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: <Widget>[
HomePage(),//首页
FindPage(),//发现
MsgPage(),//消息
UserPage(),//我的
],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
currentIndex: _currentIndex,
onTap: (newIndex) {
if (_currentIndex != newIndex) {
setState(() {
_currentIndex = newIndex;
});
}
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('首页'),
),
BottomNavigationBarItem(
icon: Icon(Icons.explore),
title: Text('发现'),
),
BottomNavigationBarItem(
icon: Icon(Icons.email),
title: Text('消息'),
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('我的'),
)
]),
);
}
}
Tab 页面代码
IndexedStack 中对应的四个页面布局如下
/// 首页
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
debugPrint('HomePage');
return Scaffold(
appBar: AppBar(title: Text('首页'),),
body: Center(child: Text('首页')),
);
}
}
/// 发现
class FindPage extends StatefulWidget {
@override
_FindPageState createState() => _FindPageState();
}
class _FindPageState extends State<FindPage> {
@override
Widget build(BuildContext context) {
debugPrint('FindPage');
return Scaffold(
appBar: AppBar(title: Text('发现'),),
body: Center(child: Text('发现')),
);
}
}
/// 消息
class MsgPage extends StatefulWidget {
@override
_MsgPageState createState() => _MsgPageState();
}
class _MsgPageState extends State<MsgPage> {
@override
Widget build(BuildContext context) {
debugPrint('MsgPage');
return Scaffold(
appBar: AppBar(title: Text('消息'),),
body: Center(child: Text('消息')),
);
}
}
///我的
class UserPage extends StatefulWidget {
@override
_UserPageState createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
@override
Widget build(BuildContext context) {
debugPrint('UserPage');
return Scaffold(
appBar: AppBar(title: Text('我的'),),
body: Center(child: Text('我的')),
);
}
}
发现问题
看上面的代码似乎很合理,但是当我们点击【发现】 Tab 时,5 个页面都进行了 rebuild,log 日志如下
是不是有些诧异?但是仔细分析主页代码,因为点击切换 Tab 时,执行了setState({})
那么主页必然会 rebuild,然后 4 个Tab 页面又是在 IndexedStack
中创建的,所以 4 个 Tab 页,也一起 rebuild 了
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: <Widget>[
HomePage(),//首页
FindPage(),//发现
MsgPage(),//消息
UserPage(),//我的
],
),
bottomNavigationBar: BottomNavigationBar(
...
onTap: (newIndex) {
if (_currentIndex != newIndex) {
setState(() {
_currentIndex = newIndex;
});
}
},
items: [
...
]),
);
解决问题
我们把 4 个 Tab 页面放到 initState
中即可
class MainPage extends StatefulWidget {
MainPage({Key key}) : super(key: key);
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
/// 当前索引
int _currentIndex = 0;
/// 页面列表
List pageList;
@override
void initState() {
///初始化 4 个 Page
pageList = <Widget>[
HomePage(), //首页
FindPage(), //发现
MsgPage(), //消息
UserPage(), //我的
];
super.initState();
}
@override
Widget build(BuildContext context) {
debugPrint('MainPage');
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: pageList,
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
currentIndex: _currentIndex,
onTap: (newIndex) {
if (_currentIndex != newIndex) {
setState(() {
_currentIndex = newIndex;
});
}
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('首页'),
),
BottomNavigationBarItem(
icon: Icon(Icons.explore),
title: Text('发现'),
),
BottomNavigationBarItem(
icon: Icon(Icons.email),
title: Text('消息'),
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('我的'),
)
]),
);
}
}
最终点击 Tab 页看看效果