目录
问题描述
使用BottomNavigationBar实现页面的类似Android中Fragment切换的效果时,发现每次切换页面的时候,上个页面都会被销毁,新的页面都会重新创建,但是有时不需要重新创建,因此需要对页面进行缓存
解决方法
1.使用IndexedStack
IndexedStack可以同时创建多个Widget然后根据index展示对应的页面,关键代码如下:
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var pages = [
WeiChatPage(),
DevicePage(),
MinePage()
];
var titles = ["首页","设备","我的"];
var currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leadingWidth: 70,
leading: currentIndex == 1 ? TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.only(left: 10)),
),
onPressed: (){},
child: Text("切换设备",style: TextStyle(
color: Colors.black,
fontSize: 14
),),
) : null,
actions: currentIndex == 1 ? [
IconButton(onPressed: (){}, icon: Icon(Icons.add,color: Colors.black,))
] : null,
backgroundColor: Colors.white,
elevation: 0.2,
centerTitle: true,
title: Text(titles[currentIndex],style: TextStyle(
color: Colors.black
),),
),
body: IndexedStack( /// 在这里修改
index: currentIndex,
children: pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
onTap: (index) {
setState(() {
currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.messenger_outlined),
label:titles[0]),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: titles[1]),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: titles[2]),
],
),
);
}
}
2.使用PageView
使用PageView可实现只缓存某个页面,这里我使用了flukit库
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
flukit: ^3.0.1 #工具类
然后将页面使用KeepAliveWrapper包裹,如下所示,这里我只包裹了WeiChatPage页面
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
/// 初始化控制器
late PageController pageController;
var pages = [
KeepAliveWrapper(child: WeiChatPage(),),
DevicePage(),
MinePage()
];
var titles = ["首页","设备","我的"];
var currentIndex = 0;
@override
void initState() {
// TODO: implement initState
super.initState();
//创建控制器的实例
pageController = new PageController(
//用来配置PageView中默认显示的页面 从0开始
initialPage: 0,
//为true是保持加载的每个页面的状态
keepPage: true,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leadingWidth: 70,
leading: currentIndex == 1 ? TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.only(left: 10)),
),
onPressed: (){},
child: Text("切换设备",style: TextStyle(
color: Colors.black,
fontSize: 14
),),
) : null,
actions: currentIndex == 1 ? [
IconButton(onPressed: (){}, icon: Icon(Icons.add,color: Colors.black,))
] : null,
backgroundColor: Colors.white,
elevation: 0.2,
centerTitle: true,
title: Text(titles[currentIndex],style: TextStyle(
color: Colors.black
),),
),
body: PageView( /// 在这里修改
// index: currentIndex,
/// 控制跳转翻页的控制器
controller: pageController,
//禁止滑动
physics: const NeverScrollableScrollPhysics(),
/// 页面滑动
/// 这里设置 PageView 页面滑动也能
onPageChanged: (index) {
setState(() {
// 更新当前的索引值
currentIndex = index;
});
},
children: pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
onTap: (index) {
// 控制 PageView 跳转到指定的页面
pageController.jumpToPage(index);
setState(() {
currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.messenger_outlined),
label:titles[0]),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: titles[1]),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: titles[2]),
],
),
);
}
}
然后我们切换页面可以看看打印输出,其中WeiChatPage只创建了一次