Flutter: BottomNavigationBar + PageView 翻页时崩溃

转载请标明出处: juejin.im/post/5b7e25…
本文出自:Wos的主页git

若是发生 '_debugUltimatePreviousSiblingOf(after, equals: _firstChild)': is not true. 的错误, 请检查是不是如下缘由形成的, 并根据下文进行修改

注意: 这篇文章版本久远, 可能再也不适用于新版本. 仅供参考, 慎用

示例:github

class _HomeContainerState extends State<HomeContainer> {
  PageController _pageController;
  int _currentIndex = 0;

  @override
  void initState() {
    super.initState();
    _pageController = new PageController();
  }
  
  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: PageView(
        children: <Widget>[
          new Container(
            child: new Page1(),
          ),
          new Container(
            child: new Page2(),
          ),
          new Container(
            child: new Page3(),
          ),
          Container(
            child: new Page4(),
          ),
        ],
        controller: _pageController,
        physics: NeverScrollableScrollPhysics(),
        onPageChanged: (int index){
          setState(() {
            _currentIndex = index;
          });
        },
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          _buildItem('page1'),
          _buildItem('page2'),
          _buildItem('page3'),
          _buildItem('page4'),
        ],
        onTap: (int index) {
          _pageController.jumpToPage(index);
        },
        currentIndex: _currentIndex,
        type: BottomNavigationBarType.fixed,
      ),
    );
  }

  _buildItem(String title){
    return BottomNavigationBarItem(
      icon: Icon(
        Icons.account_balance,
      ),
      title: Text(title),
    );
  }
}
复制代码

以上代码会形成崩溃, 报错信息以下:bash

报错信息:

Restarted app in 2,823ms.
I/flutter (24543): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (24543): The following assertion was thrown building NotificationListener<KeepAliveNotification>:
I/flutter (24543): 'package:flutter/src/rendering/object.dart': Failed assertion: line 2775 pos 14:
I/flutter (24543): '_debugUltimatePreviousSiblingOf(after, equals: _firstChild)': is not true.
I/flutter (24543): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (24543): more information in this error message to help you determine and fix the underlying cause.
I/flutter (24543): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (24543):   https://github.com/flutter/flutter/issues/new
I/flutter (24543): When the exception was thrown, this was the stack:
I/flutter (24543): #2 _RenderSliverMultiBoxAdaptor&RenderSliver&ContainerRenderObjectMixin._insertIntoChildList (package:flutter/src/rendering/object.dart)
I/flutter (24543): #3 _RenderSliverMultiBoxAdaptor&RenderSliver&ContainerRenderObjectMixin.insert (package:flutter/src/rendering/object.dart:2809:5)
I/flutter (24543): #4 RenderSliverMultiBoxAdaptor.insert (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:209:11)
I/flutter (24543): #5 SliverMultiBoxAdaptorElement.insertChildRenderObject (package:flutter/src/widgets/sliver.dart:865:18)
I/flutter (24543): #6 RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:4513:35)
I/flutter (24543): #7 RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4279:5)
I/flutter (24543): #8 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4653:11)
I/flutter (24543): #9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
I/flutter (24543): #10 Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
I/flutter (24543): #11 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #12 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #13 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3622:5)
I/flutter (24543): #14 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
I/flutter (24543): #15 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
I/flutter (24543): #16 Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
I/flutter (24543): #17 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #18 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #19 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3622:5)
I/flutter (24543): #20 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
I/flutter (24543): #21 ParentDataElement.mount (package:flutter/src/widgets/framework.dart:3955:11)
I/flutter (24543): #22 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
I/flutter (24543): #23 Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
I/flutter (24543): #24 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #25 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #26 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3622:5)
I/flutter (24543): #27 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3769:11)
I/flutter (24543): #28 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
I/flutter (24543): #29 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
I/flutter (24543): #30 Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
I/flutter (24543): #31 SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:744:36)
I/flutter (24543): #32 SliverMultiBoxAdaptorElement.performRebuild (package:flutter/src/widgets/sliver.dart:702:34)
I/flutter (24543): #33 SliverMultiBoxAdaptorElement.update (package:flutter/src/widgets/sliver.dart:671:7)
I/flutter (24543): #34 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #35 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4379:32)
I/flutter (24543): #36 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4769:17)
I/flutter (24543): #37 _ViewportElement.update (package:flutter/src/widgets/viewport.dart:192:11)
I/flutter (24543): #38 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #39 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #40 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #41 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #42 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #43 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #44 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #45 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #46 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #47 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #48 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #49 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #50 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #51 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #52 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #53 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #54 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #55 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #56 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #57 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #58 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #59 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #60 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #61 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #62 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #63 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #64 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #65 StatelessElement.update (package:flutter/src/widgets/framework.dart:3702:5)
I/flutter (24543): #66 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #67 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #68 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #69 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #70 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #71 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #72 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #73 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #74 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #75 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #76 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #77 StatelessElement.update (package:flutter/src/widgets/framework.dart:3702:5)
I/flutter (24543): #78 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #79 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #80 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #81 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #82 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #83 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #84 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #85 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #86 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #87 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #88 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #89 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #90 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #91 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4379:32)
I/flutter (24543): #92 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4769:17)
I/flutter (24543): #93 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #94 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #95 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #96 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #97 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #98 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #99 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #100 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #101 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #102 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #103 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #104 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #105 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #106 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #107 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #108 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #109 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #110 StatelessElement.update (package:flutter/src/widgets/framework.dart:3702:5)
I/flutter (24543): #111 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #112 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4661:14)
I/flutter (24543): #113 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #114 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #115 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #116 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #117 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #118 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #119 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #120 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #121 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #122 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #123 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #124 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #125 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #126 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #127 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #128 ProxyElement.update (package:flutter/src/widgets/framework.dart:3909:5)
I/flutter (24543): #129 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #130 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #131 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #132 StatefulElement.update (package:flutter/src/widgets/framework.dart:3799:5)
I/flutter (24543): #133 Element.updateChild (package:flutter/src/widgets/framework.dart:2699:15)
I/flutter (24543): #134 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
I/flutter (24543): #135 Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (24543): #136 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2242:33)
I/flutter (24543): #137 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:626:20)
I/flutter (24543): #138 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:208:5)
I/flutter (24543): #139 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter (24543): #140 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter (24543): #141 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter (24543): #142 _invoke (dart:ui/hooks.dart:120:13)
I/flutter (24543): #143 _drawFrame (dart:ui/hooks.dart:109:3)
I/flutter (24543): (elided 2 frames from class _AssertionError)
复制代码

下面先来介绍两种简单的解决方法:app

解决办法一:

jumpToPage替换为animateToPageless

_pageController.animateToPage(
  index,
  duration: Duration(milliseconds: 260),
  curve: Curves.fastOutSlowIn,
)
复制代码

简单, 可是有动画效果.ide

解决办法二:

删除onPageChanged, 经过PageController.addListener监听页面变化post

_pageController = new PageController()
  ..addListener(() {
    if (_currentIndex != _pageController.page.round()) {
      setState(() {
        _currentIndex = _pageController.page.round();
      });
    }
  });
复制代码

这种方法仅在禁用PageView的滑动操做(NeverScrollableScrollPhysics)且使用_pageController.jumpToPage进行页面切换时生效.性能

解决办法三:

使用IndexedStack替代PageView动画

解决办法四: (推荐)

  1. 新建一个文件: rebuild_layout.dartui

  2. 将下列代码拷贝到该文件

import 'package:flutter/material.dart';

class RebuildLayout extends StatefulWidget {
  final WidgetBuilder builder;
  final RebuildLayoutController controller;

  RebuildLayout({Key key, @required this.builder, @required this.controller}) : super(key: key);

  @override
  _RebuildLayoutState createState() => _RebuildLayoutState();
}

class _RebuildLayoutState extends State<RebuildLayout> {
  @override
  void initState() {
    super.initState();

    widget.controller.addListener(_onRebuild);
  }

  @override
  void didUpdateWidget(RebuildLayout oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (oldWidget.controller != widget.controller) {
      oldWidget.controller.removeListener(_onRebuild);
      widget.controller.addListener(_onRebuild);
    }
  }

  @override
  void dispose() {
    widget.controller._listeners.clear();
    super.dispose();
  }

  _onRebuild() => setState(() {});

  @override
  Widget build(BuildContext context) {
    return widget.builder(context);
  }
}

class RebuildLayoutController extends Listenable {
  List<VoidCallback> _listeners = [];

  @override
  void addListener(listener) {
    _listeners.add(listener);
  }

  @override
  void removeListener(listener) {
    _listeners.remove(listener);
  }

  notification() {
    for(var listener in _listeners){
      listener();
    }
  }
}
复制代码
  1. BottomNavigationBar外面套一层RebuildLayout
bottomNavigationBar: RebuildLayout(builder: (BuildContext context){
  return BottomNavigationBar(
    ...
    onTap: (int index) {
      _pageController.jumpToPage(index);
    },
    currentIndex: _currentIndex,
    type: BottomNavigationBarType.fixed,
  );
}, controller: _rebuildLayoutController),
复制代码
  1. initState()声明周期中建立_rebuildLayoutController
RebuildLayoutController _rebuildLayoutController;

@override
void initState() {
  super.initState();
  ...
  _rebuildLayoutController = RebuildLayoutController();
}
复制代码
  1. PageViewonPageChanged属性中调用rebuildLayoutController.notification()
body: PageView(
  ...
  onPageChanged: (int index){
    _currentIndex = index;
    rebuildLayoutController.notification();
  },
),
复制代码

RebuildLayout的思路是: 只通知其子控件重建, 而不影响其它控件.

没使用RebuildLayout以前, onPageChanged回调中会调用setState来刷新页面, 这将致使PageView和BottomNavigationBar都被重建, 形成性能损耗.

这个控件几乎是彻底解耦的, 所以能够用在不少只想局部刷新的地方.


以上, 但愿可以解决你的问题 :)

相关文章
相关标签/搜索