BottomNavigationBar切换
在Flutter应用中,导航栏切换页面后默认情况下会丢失原页面状态,即每次进入页面时都会重新初始化状态,如果在initState
中打印日志,会发现每次进入时都会输出,显然这样增加了额外的开销,并且带来了不好的用户体验(这句话是抄的)。
好了,直入正题怎么解决导航切换重绘的问题:
PageView、AutomaticKeepAliveClientMixin
两个Widget使用过程如下:
class _MyHomePageState extends State<MyHomePage>{
List<Widget> _pages;
PageController _controller;
@override
void initState() {
super.initState();
_pages = List() ..add(MessionPage()) ..add(GoodsPage())
..add(ChatPage()) ..add(MinePage());
_controller = PageController(initialPage: 0);
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _bulidBody(),
bottomNavigationBar: _buildButtomNavBar(),
);
}
Widget _bulidBody(){
return PageView.builder(
physics: NeverScrollableScrollPhysics(),//viewPage禁止左右滑动
controller: _controller,
itemCount: _pages.length,
itemBuilder: (context, index) => _pages[index]);
}
Widget _buildButtomNavBar(){
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [...],
onTap: _onSelectTab,
);
}
void _onSelectTab(int index){
_controller.jumpToPage(index);
switch(index){
case 0:{
_onLayoutSelection(LayoutType.mession);
}
break;
...
}
void _onLayoutSelection(LayoutType type){
setState(() {
_layoutSelection = type;
});
}
这里主要描述主界面如何使用pageview。然后是子界面
class MineState extends State<MinePage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(...);
这样就实现了切换tab界面不再重绘的效果了,实现很简单。下面mark一下路由跳转回来之后UI重绘的问题。
路由跳转返回UI重绘(网络版防止FutureBuilder重绘)
为啥会重绘道理跟上面类似,还有一点就是:网络请求,数据返回之前我们加载一个组件,等数据返回值后,我们重绘页面返回另一个组件
两种解决方案:
1、在构建函数之外调用Future
就是在Widget的initState()函数中完成网络数据加载,将数据赋值给一个变量(tempData),在FutureBuilder中直接去使用tempData。感觉上怪怪的,不太符合移动网络开发习惯,所以重点推荐另外一种:
2、Memoize the future(缓存起来)
import 'package:async/src/async_memoizer.dart';
class MessionState extends State<MessionPage> with AutomaticKeepAliveClientMixin {
final AsyncMemoizer _memoizer = AsyncMemoizer();
_fetchMessionList(){
return _memoizer.runOnce(() async {
List<Mession> messionList = List<Mession>();
try {
final response =
await Dio().get('${Config.BASE_URL}/mession/get_messions');
if (response.statusCode == 200) {
messionList = Mession.fromJson(response.toString());
}
return messionList;
} catch (e) {
print('MessionPage->' + e.toString());
}
return messionList;
});
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
...
body: _getList(),
);
}
Widget _getList() {
return Center(
child: FutureBuilder(
future: _fetchMessionList(),
builder: (context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error:${snapshot.error}');
} else {
return _createListView(context, snapshot);
}
}
},
),
);
}
Widget _createListView(BuildContext context, AsyncSnapshot snapshot) {
...
}
}
如何使用按照上面代码写就可以了。
网友评论