链接两个页面浏览量波动

问题描述 投票:0回答:1

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

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

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

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

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

并且一次打开其他网页浏览量后,所有错误均消失了,但是即使移除了当前网页浏览量,它也会被跳转。

[由于没有同时触发其他综合浏览量的事件,因此没有无限循环。

/// 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小部件中。

完整代码

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;
}

flutter flutter-layout
1个回答
0
投票

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

  • 维护控制器列表
  • HomePage小部件中跟踪当前垂直位置。
  • 还有当前水平网页浏览量的位置。
  • 如果窗口小部件的页面被更改并且在视口中可见,则使所有其他页面跳转到此位置。使其跳转之前,请检查它是否在小部件树中。
  • 否则,如果不在视口中,则不要应用相同的回调,因为它只应受视口中的一个(或当前正在滚动的一个)影响。
  • 初始化任何综合浏览量时,请检查当前垂直位置并跳至该页面。
  • 这效率不高,因为我将小部件树中的所有综合浏览量都保持活动状态,即使它们不可见。 (如果我提出一个有效的答案,我将更新答案)
  • 这是有效的,因为两个网页浏览量都在一个水平的单一网页浏览量中。
  • [我将提供另一个示例,其中两个页面浏览量都在视口中(例如,一行)。
  • 这可以扩展到多个页面视图,并导致一个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;
}

© www.soinside.com 2019 - 2024. All rights reserved.