连连看两个网页浏览量 [英] Link two pageviews in flutter

查看:47
本文介绍了连连看两个网页浏览量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在抖动中链接两个综合浏览量?

How to link two pageviews in flutter?

即如果其中一个进入第x页,另一个也应进入第x页.

i.e. if one of them goes to page x the other should go to page x as well.

我认为两个具有相同控制器的PageView可以解决问题. 但这似乎并非如此.

I thought two PageViews having the same controller would do the trick. But that doesn't seem to be the case.

我尝试过列出一个控制器列表,并且当某个页面浏览量的页面发生更改时,我正在所有其他页面浏览量的控制器上调用jumpToPage,但是所有其他页面浏览量最初不在窗口小部件运行时树中(它们是重新显示在屏幕之外),从而发出错误消息.

I tried having a list of controllers and when one of the pageviews' page changes, I'm calling jumpToPage on all the other pageviews' controllers but all the other PageViews are not in the widget runtime tree initially (They're outside the screen) thus giving out errors.

就我而言,PageView(children:[Pageview(...), Pageview(...)])是结构.

在我一次打开其他综合浏览量之后,所有错误均消失了,但是即使我将其移除,当前的综合浏览量也会被跳转.

And after I open the other pageviews once, the errors are all gone but the current pageview is also getting jumped even though I removed it.

由于同时触发了另一个综合浏览量的事件,因此没有无限循环.

There're no infinite loops because of the other pageview's event firing at the same time.

/// Inside a stateful widget
  PageView(
      controller: widget.controller,
      onPageChanged: (pno) {
        widget.controllers.where((x) {
          return x != widget.controllers[widget.idx];
        }).forEach((colpv) {
          colpv.controller?.jumpToPage(pno);
        });
      },
     );

这是一个最小的示例,它再现了我在做什么.在ColPageView小部件中.

This is a minimal example that reproduces what I'm doing. It's in the ColPageView widget.

完整代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  SystemChrome.setEnabledSystemUIOverlays([]);
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Experiments',
      theme: ThemeData.dark(),
      home: MyHomePage(title: 'FlutterExps'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  List<PageControllerC> _controllers;
  PageController _rowController;
  PageController _mainController;

  @override
  void initState() {
    _controllers = [
      PageControllerC(
        controller: PageController(keepPage: true),
        recorded: 0,
      ),
      PageControllerC(
        controller: PageController(keepPage: true),
        recorded: 1,
      ),
    ];
    _controllers.forEach((f) {
      f.controller.addListener(() {
        print("Listener on ${f.recorded}");
      });
    });
    _mainController = PageController();
    _rowController = PageController();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        controller: _rowController,
        children: [
          ColPageView(
            idx: 0,
            controllers: _controllers,
            controller: _mainController,
            children: <Widget>[
              ColoredWidget(
                color: Colors.cyan,
                direction: ">",
              ),
              ColoredWidget(
                color: Colors.orange,
                direction: ">>",
              ),
            ],
          ),
          ColPageView(
            idx: 1,
            controllers: _controllers,
            controller: _mainController,
            children: [
              ColoredWidget(
                color: Colors.green,
                direction: "<",
              ),
              ColoredWidget(
                color: Colors.yellow,
                direction: "<<",
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class PageControllerC {
  PageController controller;
  int recorded;
  PageControllerC({
    this.recorded,
    this.controller,
  });
}

class ColPageView extends StatefulWidget {
  final List<Widget> children;
  final List<PageControllerC> controllers;
  final int idx;
  final PageController controller;

  const ColPageView({
    Key key,
    this.children = const <Widget>[],
    @required this.controllers,
    @required this.idx,
    this.controller,
  }) : super(key: key);

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

class _ColPageViewState extends State<ColPageView> {
  @override
  Widget build(BuildContext context) {
    return PageView(
      controller: widget.controllers[widget.idx].controller,
    //   controller: widget.controller,
      scrollDirection: Axis.vertical,
      children: widget.children,
      onPageChanged: (pno) {
        widget.controllers.where((x) {
          return x != widget.controllers[widget.idx];
        }).forEach((colpv) {
          // if (colpv != widget.controllers[widget.idx]) {
          colpv.controller?.jumpToPage(pno);
          // }
          // else{
          print("memmem ${widget.idx}");
          // }
        });
        print("col-${widget.idx} changed to $pno");
      },
    );
  }
}

class ColoredWidget extends StatefulWidget {
  final Color color;
  final String direction;

  const ColoredWidget({
    Key key,
    @required this.color,
    @required this.direction,
  }) : super(key: key);

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

class _ColoredWidgetState extends State<ColoredWidget>
    with AutomaticKeepAliveClientMixin<ColoredWidget> {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container(
        color: widget.color,
        child: Center(
          child: Text(
            widget.direction,
            style: TextStyle(
              fontSize: 100,
              color: Colors.black,
            ),
          ),
        ));
  }

  @override
  bool get wantKeepAlive => true;
}

推荐答案

我能够链接两个pageviews,因为它们都位于pageview中.

I was able to link two pageviews given that they both reside in a pageview.

注意:它们是离散链接的.

Note: They're discretely linked.

  • 维护控制器列表
  • HomePage小部件中跟踪当前的垂直位置.
  • 还有当前水平网页浏览量的位置.
  • 如果窗口小部件的页面被更改并且在视口中可见,则使所有其他页面跳转到此位置.使其跳转之前,请检查它是否在小部件树中.
  • 否则,如果不在视口中,则不要应用相同的回调,因为它只应受视口中的一个(或当前滚动的一个)影响.
  • 初始化任何综合浏览量时,请检查当前的垂直位置并跳转到该页面.
  • 这效率不高,因为即使小部件树中的所有网页浏览不可见,它们也会保持活动状态. (如果我提出一个有效的答案,我将更新答案)
  • 之所以可行,是因为两个网页浏览量都在一个水平的单一网页浏览量中.
  • 我将尝试提供另一个示例,其中两个网页浏览都在视口中(例如,一行),并且链接是连续的.
  • 这可以扩展到多个页面视图,并导致全屏GridView .
    • Maintain a list of controllers
    • Track the current vertical position in the HomePage widget.
    • And also the current horizontal pageview's position.
    • If a widget's page is being changed and it is visible in the viewport then make all other pages jump to where this goes. Check if it is in the widget tree before making it jump.
    • Else if it's not in the viewport don't apply the same callback as it should only be affected by the one in the viewport (or the currently scrolling one).
    • When initializing any pageview check the current vertical position and jump to that page.
    • This is not efficient as I'm keeping all the pageviews in the widget tree alive even if they are not visible. (I will update the answer if I come up with one that is efficient)
    • This is working because both pageviews are in a single pageview which is horizontal.
    • I will try to provide another example where both the pageviews are in the viewport (in a row for example) and the linking is continuous.
    • This can be extended to multiple page views and which leads to a fullscreen GridView.
    • 完整代码.

      import 'package:flutter/material.dart';
      import 'package:flutter/services.dart';
      
      void main() {
        SystemChrome.setEnabledSystemUIOverlays([]);
        runApp(MyApp());
      }
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            title: 'Flutter Experiments',
            theme: ThemeData.dark(),
            home: MyHomePage(title: 'FlutterExps'),
          );
        }
      }
      
      class MyHomePage extends StatefulWidget {
        MyHomePage({Key key, this.title}) : super(key: key);
        final String title;
      
        @override
        _MyHomePageState createState() => _MyHomePageState();
      }
      
      class _MyHomePageState extends State<MyHomePage> {
        List<PageController> _controllers;
        PageController _rowController;
        ValueNotifier<int> _horizPage = ValueNotifier(0);
        ValueNotifier<int> _vertPage = ValueNotifier(0);
      
        @override
        void initState() {
          _controllers = [
            PageController(keepPage: true),
            PageController(keepPage: true),
          ];
          _rowController = PageController();
          _horizPage.value = _rowController.initialPage;
          super.initState();
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: PageView(
              controller: _rowController,
              onPageChanged: (pno) {
                setState(() {
                  _horizPage.value = pno;
                });
              },
              children: [
                ColPageView(
                  idx: 0,
                  currHoriz: _horizPage,
                  vertstate: _vertPage,
                  controllers: _controllers,
                  children: <Widget>[
                    ColoredWidget(
                      color: Colors.cyan,
                      direction: ">",
                    ),
                    ColoredWidget(
                      color: Colors.orange,
                      direction: ">>",
                    ),
                  ],
                ),
                ColPageView(
                  idx: 1,
                  currHoriz: _horizPage,
                  vertstate: _vertPage,
                  controllers: _controllers,
                  children: [
                    ColoredWidget(
                      color: Colors.green,
                      direction: "<",
                    ),
                    ColoredWidget(
                      color: Colors.yellow,
                      direction: "<<",
                    ),
                  ],
                ),
              ],
            ),
          );
        }
      }
      
      class ColPageView extends StatefulWidget {
        final int idx;
        final List<Widget> children;
        final List<PageController> controllers;
        final ValueNotifier<int> currHoriz;
        final ValueNotifier<int> vertstate;
      
        const ColPageView({
          Key key,
          this.children = const <Widget>[],
          @required this.controllers,
          @required this.currHoriz,
          @required this.vertstate,
          @required this.idx,
        }) : super(key: key);
      
        @override
        _ColPageViewState createState() => _ColPageViewState();
      }
      
      class _ColPageViewState extends State<ColPageView> {
        @override
        void initState() {
          widget.controllers[widget.idx] = PageController(
            initialPage: widget.vertstate.value ?? 0,
            keepPage: true,
          );
      
          super.initState();
        }
      
        @override
        Widget build(BuildContext context) {
          return PageView(
            controller: widget.controllers[widget.idx],
            scrollDirection: Axis.vertical,
            children: widget.children,
            onPageChanged: (widget.idx == widget.currHoriz.value)
                ? (pno) {
                    widget.controllers.forEach((colpv) {
                      if (colpv != widget.controllers[widget.idx]) {
                        if (colpv.hasClients && colpv.page != pno) {
                          colpv.jumpToPage(pno);
                        }
                      }
                    });
                    // Set latest vertical position
                    widget.vertstate.value = pno;
      
                    // print("col-${widget.idx} changed to $pno");
                    // set horizontal coord to be null
                    // As we've finished dealing with it
                    widget.currHoriz.value = null;
                  }
                : null,
          );
        }
      }
      
      class ColoredWidget extends StatefulWidget {
        final Color color;
        final String direction;
      
        const ColoredWidget({
          Key key,
          @required this.color,
          @required this.direction,
        }) : super(key: key);
      
        @override
        _ColoredWidgetState createState() => _ColoredWidgetState();
      }
      
      class _ColoredWidgetState extends State<ColoredWidget>
          with AutomaticKeepAliveClientMixin<ColoredWidget> {
        @override
        Widget build(BuildContext context) {
          super.build(context);
          return Container(
              color: widget.color,
              child: Center(
                child: Text(
                  widget.direction,
                  style: TextStyle(
                    fontSize: 100,
                    color: Colors.black,
                  ),
                ),
              ));
        }
      
        @override
        bool get wantKeepAlive => true;
      }
      
      

      这篇关于连连看两个网页浏览量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆