如何将两个或多个PageView与不同的控制器同步

时间:2020-10-20 11:53:22

标签: flutter controller

我有2个具有不同viewportFraction的PageViews。有什么方法可以滚动其中一个PageView,而另一个可以滚动在同一页面或偏移量上吗?

还问,是否可以将PageView控制在代码中的偏移量的中间?

class MyPageControllers extends StatefulWidget {
  @override
  _MyPageControllersState createState() => _MyPageControllersState();
}

class _MyPageControllersState extends State<MyPageControllers> {

  PageController _controller1;
  PageController _controller2;

  Widget _itemBuilder(BuildContext context, int index) => Container(
    color: Colors.primaries[index % Colors.primaries.length],
    child: Center(
      child: Text(
        index.toString(),
        style: TextStyle(color: Colors.white, fontSize: 60),
      ),
    ),
  );

  @override
  void initState() {
    super.initState();
    _controller1 = PageController(viewportFraction: 0.8);
    _controller2 = PageController(viewportFraction: 0.5);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: PageView.builder(
            controller: _controller1,
            itemBuilder: _itemBuilder,
          ),
        ),
        SizedBox(
          height: 40,
        ),
        Expanded(
          child: PageView.builder(
            controller: _controller2,
            itemBuilder: _itemBuilder,
          ),
        ),
      ],
    );
  }
}

enter image description here

2 个答案:

答案 0 :(得分:1)

因此,您需要在call ..\venv\Scripts\activate.bat pytest -v src/datasets_test.py::TestDatasetsOperations::test_dataset_add 小部件之一的PageViewPageController)上附加一个侦听器,然后更改另一个{{1} }小部件的_controller1offset)。

初始化控制器后,您需要在PageView中添加这段代码:

PageController

更新后的答案(已选择页面同步):

_controller2

更新后的答案(具有手动滚动检测功能):

initState

答案 1 :(得分:0)

我发现受@yusufpats解决方案启发的黑客解决方案。我在下面描述了更多细节:

将侦听器添加到每个PageController

这部分有点棘手,因为当控制器彼此听时,页面实际上会卡住并且无法滚动(为什么?)。我添加bool来检查正在滚动的滚动条并需要收听。

bool _isPage1Scrolling;
bool _isPage2Scrolling;

void initState() {
  _isPage1Scrolling = false;
  _isPage2Scrolling = false;

  ...
  _controller1.addListener(() {
    if(_isPage1Scrolling){
      // Control _controller2
    }
  }

  _controller2.addListener(() {
    if(_isPage1Scrolling){
      // Control _controller2
    }
  }

如何控制其他PageController?

这是最难的部分,因为如果我使用animateTojumpTo,则“受控控制器”看起来很奇怪并且看起来不太流畅。这是设计使然,当用户调用这两个函数时,页面在很短的时间到达该位置(反弹回到稳定的页面位置)后,始终会转到“ BallisticScrollActivity”。我从控制器内的ScrollPosition中找到了一些解决方案,但似乎只有最后一个可以做得很好,而且没有警告:

  1. jumpToWithoutSettling (值):已过时,可能会导致错误(我尚不了解)
  2. forcePixels (值):受保护的功能(为什么我仍然可以使用它?)
  3. correctPixels (值):这将在不通知的情况下移动像素。所以我必须自己通知听众。

我将offset用作第一页的班次,并按viewportFraction计算另一页的班次

// Control _controller2

// _controller2.position.jumpToWithoutSettling(... 
// _controller2.position.forcePixels(...

_controller2.position.correctPixels(_controller1.offset * _controller2.viewportFraction / _controller1.viewportFraction);
_controller2.position.notifyListeners();
 

最后听听PageView本身

我使用NotificationListener而不使用GestureDetector,因为onTapDownonTapUp不适合滚动通知。有时,我快速触摸并滚动时没有onTapDown事件。

我研究了通知类型并在里面找到了一些东西

  1. 当我从头开始拖动时,它会提供一个带有方向的UserScrollNotification
  2. 当页面变得稳定时,它会提供另一个方向为空闲的UserScrollNotification

可能有更好的方法来检测它。我只是想出一种简单的方法。

...
child: NotificationListener(
  onNotification: (notification){
    if(notification is UserScrollNotification){
      if(notification.direction != ScrollDirection.idle){
        (_controller2.position as ScrollPositionWithSingleContext).goIdle();
        _isPage1Scrolling = true;
        _isPage2Scrolling = false;
      }
      else{
        _isPage1Scrolling = false;
      }
    }
    return false;
  },
  child: PageView.builder(
    ...

也许有人注意到以下行:

(_ controller2.position as ScrollPositionWithSingleContext).goIdle();

此行用于If I drag the firs PageView and then drag anther PageView before the first one return to a stable position边缘保护套。第一个PageView的滚动位置仍处于BallisticScrollActivity状态,我需要强制使其空闲才能控制它。

欢迎任何建议!