美文网首页
4、Flutter 防止BottomNavigationBar切

4、Flutter 防止BottomNavigationBar切

作者: LogMan | 来源:发表于2019-05-06 16:09 被阅读0次

    BottomNavigationBar切换

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

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

    相关文章

      网友评论

          本文标题:4、Flutter 防止BottomNavigationBar切

          本文链接:https://www.haomeiwen.com/subject/xgfdoqtx.html