【问题标题】:How to use a Pagview PageController in Flutter using Redux如何使用 Redux 在 Flutter 中使用 Pagview PageController
【发布时间】:2019-07-18 08:50:00
【问题描述】:

我在 Flutter 中使用 Redux(我刚刚开始学习这两种方法)。我一直在试图弄清楚如何使用 PageView 的 PageController 在 PageView 的页面之间切换。

但是,每当我尝试使用 PageController.jumpToPage() 函数时,都会收到一个异常说明:

“在最终确定小部件树时引发以下断言:当小部件树被锁定时调用 setState() 或 markNeedsBuild()。”

当我尝试在 reducer 中调用 PageController.jumpToPage() 时,它会导航到页面视图中的页面;但异常被抛出。

我也尝试在reducer中构建一个新的PageController,并将PageController的初始页面属性设置为所需的页面,但这似乎没有任何作用。

我对如何自己解决这个问题已经没有想法了,所以我想我会在这里问。任何帮助将不胜感激。

我整理了一个快速示例,展示了我正在尝试做的事情:

import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final store = Store<AppState>(appReducer,
      initialState: AppState.initial(), middleware: []);

  @override
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: MaterialApp(
        title: 'PageView Example With Redux',
        home: MyPageViewContainer(),
      ),
    );
  }
}

class AppState {
  final List<Widget> pageViewList;
  final PageController pageController;

  AppState({
    this.pageViewList,
    this.pageController,
  });

  factory AppState.initial() {
    return AppState(
      pageViewList: [
        PageOne(),
        PageTwo(),
      ],
      pageController: PageController(initialPage: 0),
    );
  }

  AppState copyWith({
    List<Widget> pageViewList,
    PageController pageController,
  }) {
    return AppState(
      pageViewList: pageViewList ?? this.pageViewList,
      pageController: pageController ?? this.pageController,
    );
  }
}

AppState appReducer(AppState state, action) {   

  if (action is NavigateToPageOneAction) {
      state.pageController.jumpToPage(0);
    return state;
  }
  else if (action is NavigateToPageTwoAction) {
    state.pageController.jumpToPage(1);
    return state;
  }
  else {
    return state;
  }      
}

class NavigateToPageOneAction {}

class NavigateToPageTwoAction {}

class MyPageView extends StatelessWidget {
  final List<Widget> pageViewList;
  final PageController pageController;
  final Function onPageChanged;

  MyPageView({
    this.pageViewList,
    this.pageController,
    this.onPageChanged,
  });

  @override
  Widget build(BuildContext context) {
    return PageView(
      controller: pageController,
      children: pageViewList,
      onPageChanged: onPageChanged,
    );
  }
}

class MyPageViewContainer extends StatelessWidget {
  MyPageViewContainer({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, _MyPageViewModel>(
      converter: (Store<AppState> store) => _MyPageViewModel.create(store),
      builder: (BuildContext context, _MyPageViewModel vm) {
        return MyPageView(
          pageViewList: vm.pageViewList,
          pageController: vm.pageController,
        );
      },
    );
  }
}

class _MyPageViewModel {
  final List<Widget> pageViewList;
  final PageController pageController;
  final Function onPageChanged;

  _MyPageViewModel({
    this.pageViewList,
    this.pageController,
    this.onPageChanged,
  });

  factory _MyPageViewModel.create(Store<AppState> store) {
    _onPageChanged() {}

    return _MyPageViewModel(
      pageViewList: store.state.pageViewList,
      pageController: store.state.pageController,
      onPageChanged: _onPageChanged(),
    );
  }
}

class PageOne extends StatelessWidget {
  PageOne();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page One"),
      ),
      backgroundColor: Colors.black,
      body: Column(),
      drawer: MyDrawer(),
    );
  }
}

class PageTwo extends StatelessWidget {
  PageTwo();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page Two"),
      ),
      backgroundColor: Colors.blue,
      body: Column(),
      drawer: MyDrawer(),
    );
  }
}

class MyDrawer extends StatelessWidget {
  MyDrawer({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, _MyDrawerViewModel>(
      converter: (Store<AppState> store) => _MyDrawerViewModel.create(store),
      builder: (BuildContext context, _MyDrawerViewModel vm) {
        return Drawer(
          child: ListView(
            children: <Widget>[
              Container(
                child: ListTile(
                  title: Text(vm.pageOneText),
                  onTap: vm.pageOneOnTap,
                ),
              ),
              Container(
                child: ListTile(
                  title: Text(vm.pageTwoText),
                  onTap: vm.pageTwoOnTap,
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

class _MyDrawerViewModel {
  final String pageOneText;
  final String pageTwoText;
  final Function pageOneOnTap;
  final Function pageTwoOnTap;

  _MyDrawerViewModel({
    this.pageOneText,
    this.pageTwoText,
    this.pageOneOnTap,
    this.pageTwoOnTap,
  });

  factory _MyDrawerViewModel.create(Store<AppState> store) {
    _goToPageOne() {

     store.dispatch(NavigateToPageOneAction());
    }

   _goToPageTwo() {

     store.dispatch(NavigateToPageTwoAction());
   }

    return _MyDrawerViewModel(
      pageOneText: "Page One",
      pageTwoText: "Page Two",
      pageOneOnTap: _goToPageOne,
      pageTwoOnTap: _goToPageTwo,
    );
  }
}

【问题讨论】:

  • 我们似乎以不同的方式使用 Redux。你可以看看我的例子:github.com/lhcdims/statemanagement02
  • @KennethLi 我看到我们确实有不同的方法,我一定会更详细地看看你的项目,看看我能学到什么,我遵循了我从教程中学习的模式flutterbyexample.com 和其他人。我已经能够使用 Navigator 导航到各个页面,但我试图弄清楚如何使用其 PageController 在 PageView 小部件内的页面之间切换。查看您的示例,如果您将所有三个页面放入 PageView 并尝试使用 Drawer 中的 OnTap 事件导航到其中的页面,您将如何处理?

标签: redux flutter


【解决方案1】:

我似乎已经找到了解决问题的方法。我在这篇文章中看到了答案:Flutter: setState() or markNeedsBuild() called when widget tree was locked... during orientation change

在那篇文章中,当抽屉打开时,在纵向和横向模式之间切换时,OP 遇到了同样的错误。该帖子中的答案建议在更改视图模式之前调用 Navigator.pop() (关闭抽屉)。

所以我尝试了一下,并在使用 PageController 的 .jumpToPage 方法之前使用 Navigator.pop() 关闭了我的 Drawer。这似乎有效,并允许我使用来自 Drawer 的 onTap 事件在 PageView 的页面之间导航,而不会抛出“在完成小部件树时抛出以下断言:当小部件树被锁定时调用 setState() 或 markNeedsBuild() " 例外。

我假设这意味着当抽屉打开时,小部件树被置于锁定状态。

希望这对某人有所帮助,因为我花了一段时间才弄清楚。

【讨论】:

    【解决方案2】:

    @布劳

    有时事件发生在您构建的任何小部件之外。例如(1)增加“全局计数器”的计时器,该计数器将显示在许多页面/小部件中(2)从套接字服务器发送的消息,在接收到此消息/事件时,用户可能在任何地方(任何页面/小部件),并且您不知道在哪里“设置状态”(或者小部件实际上不存在,因为用户不在该页面上)

    我已经构建了 2 个示例来演示如何使用 Redux 来解决此类问题:

    示例 1:(当外部事件触发时,使用多线程计时器“setState”小部件)

    https://github.com/lhcdims/statemanagement01

    示例 2:(在外部事件触发时使用 Redux 刷新小部件)

    https://github.com/lhcdims/statemanagement02

    演示屏幕截图:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2018-12-30
      • 2021-08-27
      • 1970-01-01
      • 2018-07-05
      • 2019-04-16
      • 2020-05-17
      相关资源
      最近更新 更多