4、Flutter 防止BottomNavigationBar切换、返回页面重绘

BottomNavigationBar切换

Flutter应用中,导航栏切换页面后默认情况下会丢失原页面状态,即每次进入页面时都会重新初始化状态,如果在initState中打印日志,会发现每次进入时都会输出,显然这样增加了额外的开销,并且带来了不好的用户体验(这句话是抄的)。
好了,直入正题怎么解决导航切换重绘的问题:
PageViewAutomaticKeepAliveClientMixin
两个Widget使用过程如下:

class _MyHomePageState extends State{
  List _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 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 with AutomaticKeepAliveClientMixin {
  final AsyncMemoizer _memoizer = AsyncMemoizer();
_fetchMessionList(){
    return _memoizer.runOnce(() async {
      List messionList = List();
      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) {
    ...
  }
}

如何使用按照上面代码写就可以了。

你可能感兴趣的:(4、Flutter 防止BottomNavigationBar切换、返回页面重绘)