在 Flutter 的 PageView 模块中没有正确设置 PageController。弹出职位非空错误

Posted

技术标签:

【中文标题】在 Flutter 的 PageView 模块中没有正确设置 PageController。弹出职位非空错误【英文标题】:PageController not set properly within the PageView module in Flutter. Positions not empty error popping up 【发布时间】:2020-09-26 02:10:05 【问题描述】:

我开始使用 Flutter 框架进行编程,并立即注意到出现了一个奇怪的问题(请参阅下文了解更多信息)。

在以下情况下会出现问题: 返回MainScreen 并尝试通过按下按钮从PageView 中的屏幕切换来从PageView 索引更改后,我收到此错误:

[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 110 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.

这是我的主屏幕:

class MainScreen extends StatefulWidget 
  @override
  State<StatefulWidget> createState() => MainScreenState();


class MainScreenState extends State<MainScreen> 
  PageController _controller;

  void _onLoad() 
    _controller = PageController();
    ShareBloc.getInstance().pageViewIndexStream.listen((index) 
      _controller.animateToPage(index,
          duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
    );
  

  @override
  void dispose() 
    _controller.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    _onLoad();

    return PageView(
      controller: _controller,
      physics: NeverScrollableScrollPhysics(),
      children: [
        FirstScreen(),
        SecondScreen(),
      ],
    );
  

这是我的RxDart Sharable 文件:

import 'package:rxdart/rxdart.dart';

class ShareBloc 
  static ShareBloc _instance;
  BehaviorSubject<dynamic> _subjectCounter;

  static ShareBloc getInstance() 
    if (_instance == null) _instance = ShareBloc();
    return _instance;
  

  ShareBloc() 
    _subjectCounter = new BehaviorSubject<dynamic>();
  

  Stream<dynamic> get getStream => pageViewIndexStream.stream;

  void onShare(dynamic data) 
    _subjectCounter.sink.add(data);
  

  void dispose() 
    if (_subjectCounter != null) 
      _subjectCounter.close();
      _instance = null;
    
  

谁能告诉我我在这里做错了什么?

【问题讨论】:

build 方法可以多次重建(比如弹出和返回页面时)。当发生这种情况时 _onLoad() 再次运行创建另一个页面控制器并创建一个新的侦听器而不先处理旧的侦听器,尝试将 _onLoad 移动到 initState 并检查错误是否消失 是的,我也尝试过这种方法。看来之前的控制器还在 PageView 模块中。那么,如何替换它而不在每次进入我的页面时都弹出错误? 【参考方案1】:
//This will run just once
@override
void initState() 
    super.initState();
    //This code is the same as your _onLoad method, you don't neet to run it on the build method anymore
    _controller = PageController();
    ShareBloc.getInstance().pageViewIndexStream.listen((index) 
      _controller.animateToPage(index,
          duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
    );

就像 dispose 方法一样,StatefulWidget 有一个 initState 方法,它只运行一次(当它被插入到树中时)。之后,当 build 方法再次运行时,此代码将不会运行。

【讨论】:

我已经找到了解决办法!在继续之前,您需要检查控制器是否有客户端。我确实把它放在了 initState 方法中。 是的,如果您多次运行代码,则需要在添加另一个侦听器之前检查是否有任何客户端,在 init 状态下可能是多余的,因为您正在那里创建控制器并且从不添加侦听器再次。还有一个问题,你在哪里创建 pageViewIndexStream.stream?我看到你在小部件和集团中都使用了它,但我从来没有看到它来自哪里 在 bloc 文件中:Stream get getStream => pageViewIndexStream.stream;【参考方案2】:

为我解决这个问题的正确方法是包装这部分:

ShareBloc.getInstance().pageViewIndexStream.listen((index) 
      _controller.animateToPage(index,
          duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
    );

与:

ShareBloc.getInstance().pageViewIndexStream.listen((index) 
      if (_controller.hasClients)  // <-- this is the fix!
        _controller.animateToPage(index,
            duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
      
    );

【讨论】:

以上是关于在 Flutter 的 PageView 模块中没有正确设置 PageController。弹出职位非空错误的主要内容,如果未能解决你的问题,请参考以下文章

在垂直PageView中包装不同高度的项目 - Flutter

在 Flutter 中创建双向 PageView 滚动?

flutter 基于pageview 制作上下轮播文字功能

Flutter中如何在PageView中正确使用GoogleMap

带有 PageView 构建器的 Flutter 中的 Tinder swiper

Flutter - 如何制作 PageView 和 ListView?