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都被重建, 形成性能損耗.

這個控件幾乎是徹底解耦的, 所以能夠用在不少只想局部刷新的地方.


以上, 但願可以解決你的問題 :)

相關文章
相關標籤/搜索