无法在 Flutter 中的 PageController 上跳转到页面

Posted

技术标签:

【中文标题】无法在 Flutter 中的 PageController 上跳转到页面【英文标题】:Can't jumpToPage on PageController in Flutter 【发布时间】:2021-04-04 10:05:31 【问题描述】:

我已经构建了一个 Scaffold 屏幕,其中有一个 PageView 在 body 和一个 bottomNavigationBar。

我还为此页面构建了 Cubit + State 管理器。

当屏幕第一次打开时,我希望触发 API 调用。我还希望选择选项卡 1(在 PageView 和 bottomNavigationBar 上)。 当 API 返回响应时,我希望事件监听器更新屏幕并选择选项卡 0。

这适用于底部导航栏,但我在更新 PageView 时遇到问题。这是我的代码:

class HomeScreen extends StatefulWidget 
  @override
  _HomeScreenState createState() => _HomeScreenState();


class _HomeScreenState extends State<HomeScreen> 
  int _page = 1;
  PageController _c;
  double iconSize = 32;
  bool forceCourseEnrolment = true;

  @override
  void initState() 
    _c = new PageController(
      initialPage: 1,
      keepPage: false,
    );
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return BlocConsumer<HomeScreenCubit, HomeScreenState>(
        listener: (context, state) 
      debugPrint("listener received something");
      if (state is DataRetrieved) 
        state.enrolledCourses.length > 0
            ? forceCourseEnrolment = false
            : forceCourseEnrolment = true;
        state.enrolledCourses.length > 0 ? _page = 0 : _page = 1;
        var hasClients = this._c.hasClients;
        debugPrint("this._c.hasClients $hasClients");
        // This prints: this._c.hasClients false
        // Enabling this line:
        // this._c.jumpToPage(_page);
        // leads to:
        // [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 112 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
       
    , builder: (context, state) 
      if (state is HomeScreenInitial) 
        context.bloc<HomeScreenCubit>().retrieveData();
        return Scaffold(
            body: SpinKitChasingDots(
          color: COLOR_main_purple,
          size: 50.0,
        ));
      
      return Scaffold(
          body: PageView(
            controller: _c,
            onPageChanged: (newPage) 
              setState(() 
                this._page = newPage;
              );
            ,
            physics: NeverScrollableScrollPhysics(),
            children: [
              PurchasedCoursesTab(),
              ElearningTab(),
              MyPracticeTab(),
              ProfileTab(),
            ],
          ),
          bottomNavigationBar: SizedBox(
            height: 80,
            child: Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.only(
                      topRight: Radius.circular(30),
                      topLeft: Radius.circular(30)),
                  boxShadow: [
                    BoxShadow(
                        color: Colors.black38.withOpacity(0.1),
                        spreadRadius: 0,
                        blurRadius: 25),
                  ],
                ),
                child: ClipRRect(
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(30.0),
                    topRight: Radius.circular(30.0),
                  ),
                  child: BottomNavigationBar(
                    currentIndex: _page,
                    onTap: (index) 
                      if (forceCourseEnrolment == false) 
                        this._c.animateToPage(index,
                            duration: const Duration(milliseconds: 250),
                            curve: Curves.easeInOut);
                      
                    ,
                    type: BottomNavigationBarType.fixed,
                    backgroundColor: Colors.white,
                    items: <BottomNavigationBarItem>[
                      BottomNavigationBarItem(
                          // title: Text(""),
                          title: showIndicator(_page == 0),
                          icon: Container(
                            width: iconSize,
                            height: iconSize,
                            child: SvgPicture.asset('assets/images/ic_run.svg',
                                color: _page == 0
                                    ? COLOR_main_purple
                                    : forceCourseEnrolment == false
                                        ? Colors.black
                                        : COLOR_main_text_grey_with_opacity),
                          )),
                      BottomNavigationBarItem(
                          title: showIndicator(_page == 1),
                          icon: Container(
                            width: iconSize,
                            height: iconSize,
                            child: SvgPicture.asset(
                                'assets/images/ic_e_learning.svg',
                                color: _page == 1
                                    ? COLOR_main_purple
                                    : Colors.black),
                          )),
                      BottomNavigationBarItem(
                          title: showIndicator(_page == 2),
                          icon: Container(
                            width: iconSize,
                            height: iconSize,
                            child: SvgPicture.asset(
                                'assets/images/ic_journal.svg',
                                color: _page == 2
                                    ? COLOR_main_purple
                                    : forceCourseEnrolment == false
                                        ? Colors.black
                                        : COLOR_main_text_grey_with_opacity),
                          )),
                      BottomNavigationBarItem(
                          title: showIndicator(_page == 3),
                          // title: Text(_page == 3 ? "•" : "", style: TextStyle(
                          //     color: COLOR_main_purple, fontSize: 24.0)),
                          icon: Container(
                            width: iconSize,
                            height: iconSize,
                            child: SvgPicture.asset(
                                'assets/images/ic_gamification.svg',
                                color: _page == 3
                                    ? COLOR_main_purple
                                    : forceCourseEnrolment == false
                                        ? Colors.black
                                        : COLOR_main_text_grey_with_opacity),
                          )),
                    ],
                  ),
                )),
          ));
    );
  

当我尝试在 BlocConsumer 的侦听器中更改页面时遇到的错误:

[错误:flutter/lib/ui/ui_dart_state.cc(177)] 未处理的异常: 'package:flutter/src/widgets/scroll_controller.dart': 失败 断言:第 112 行 pos 12:'_positions.isNotEmpty':ScrollController 未附加到任何滚动视图。

【问题讨论】:

【参考方案1】:

发现我可以通过将以下内容添加到侦听器来使其工作:

  if (state is DataRetrieved) 
    state.enrolledCourses.length > 0
        ? forceCourseEnrolment = false
        : forceCourseEnrolment = true;
    state.enrolledCourses.length > 0 ? _page = 0 : _page = 1;
    Future.delayed(Duration(milliseconds: 50), () 
      if (this._c.hasClients) 
        this._c.jumpToPage(_page);
      
    );
   

我发现这是一个丑陋的解决方案,所以我不会将此标记为答案。如果您知道更好的处理方法,请告诉我。

【讨论】:

【参考方案2】:

您可以尝试删除此代码吗?如果需要显示加载,可以尝试将其添加到 PurchasedCoursesTab 中。

      if (state is HomeScreenInitial) 
        context.bloc<HomeScreenCubit>().retrieveData();
        return Scaffold(
            body: SpinKitChasingDots(
              color: COLOR_main_purple,
              size: 50.0,
            ));
      

出现此问题是因为此时您的 PageController 未附加到 PageView。

【讨论】:

以上是关于无法在 Flutter 中的 PageController 上跳转到页面的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中的 AlertDialog 小部件无法使用 setState 功能

在 Flutter 中导航后无法关注新页面中的 TextField

VS Code 无法识别 Flutter 中的单元测试

Flutter中的参数类型“String”无法分配给参数类型“Uri”[重复]

Flutter中的Webview无法正常工作,出现平台错误

Android Studio (Windows) 中的 Flutter 错误:无法识别的选项:--add-opens