嵌套PageView:当内部PageView到达末尾时,更改外部PageView

时间:2020-03-05 11:06:17

标签: flutter

考虑一下PageView的用法,我们在另一个PageView中有一个用法:

PageView(
  children: [
    Container(color: Colors.red),
    Column(
      children: [
        Text('Title'),
        PageView(
          children: [
            Container(color: Colors.green),
            Container(color: Colors.yellow),
          ],
        ),
      ],
    )
  ],
);

这种架构将使我们能够在外部PageView到内部PageView之间过渡。但是一旦到达内部PageView,我们就无法离开了。

以下是展示它的gif:

enter image description here

在这样的体系结构中,我们不能将两个PageView合并为一个,因为内部的PageView不会填满屏幕

如何在允许从两个PageView过渡而不会卡住的同时取得相似的结果?

2 个答案:

答案 0 :(得分:0)

一种简单的方法是使用Notification侦听器和animateToPage:

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Container(
      color: Colors.yellow,
      child: PageView(
        controller: _parentController,
        children: [
          Container(
            color: Colors.green,
            child: Center(
              child: Text('0'),
            ),
          ),
          NotificationListener<OverscrollNotification>(
            onNotification: (notification) {
              if (notification.overscroll < 0)
                _parentController.animateToPage(0,
                    duration: Duration(milliseconds: 400),
                    curve: Curves.easeInOutQuart);
              if (notification.overscroll > 0)
                _parentController.animateToPage(2,
                    duration: Duration(milliseconds: 400),
                    curve: Curves.easeInOutQuart);
              return false;
            },
            child: PageView(
              children: [
                Container(
                  color: Colors.green,
                  child: Center(child: Text('2: 0')),
                ),
                Container(
                  color: Colors.blue,
                  child: Center(child: Text('2: 1')),
                ),
              ],
            ),
          ),
          Container(
            color: Colors.red,
            child: Center(
              child: Text('2'),
            ),
          ),
        ],
      ),
    ),
  );
}

答案 1 :(得分:0)

通过使用 NotificationListener 控制页面视图,我有一个使用 PageController 的解决方法。用户实际控制较低的 PageView 并将偏移量传递给较高的 PageView。

  final _pageController1 = PageController(); // Controlled
  final _pageController2 = PageController(); // Controller

  @override
  Widget build(BuildContext context) {
    var leftOverScroll = 0.0;  // total over-scroll offset on left side

    return PageView(
      controller: _pageController1,
      children: [
        Container(color: Colors.red),
        Column(
          children: [
            Text('Title'),
            Expanded(
              child: NotificationListener(
                onNotification: (notification){                   
                  // over scroll to the left side
                  if (notification is OverscrollNotification && notification.overscroll < 0) {
                    leftOverScroll += notification.overscroll;
                    _pageController1.position.correctPixels(_pageController1.position.pixels + notification.overscroll);
                    _pageController1.position.notifyListeners();
                  }
                  
                  // scroll back after over scrolling
                  if (leftOverScroll < 0) {
                    if (notification is ScrollUpdateNotification) {
                      final newOverScroll = math.min(notification.metrics.pixels + leftOverScroll, 0.0);
                      final diff = newOverScroll - leftOverScroll;
                      _pageController1.position.correctPixels(_pageController1.position.pixels + diff);
                      _pageController1.position.notifyListeners();
                      leftOverScroll = newOverScroll;
                    }
                    _pageController2.position.correctPixels(0);
                    _pageController2.position.notifyListeners();
                  }
                  
                  // release
                  if(notification is UserScrollNotification && notification.direction == ScrollDirection.idle && leftOverScroll != 0){
                      _pageController1.previousPage(curve: Curves.ease, duration: Duration(milliseconds: 400));
                      leftOverScroll = 0;
                  }
                  return false;
                },
                child: PageView(
                  controller: _pageController2,
                  children: [
                    Container(color: Colors.green),
                    Container(color: Colors.yellow),
                  ],
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }

关于如何避免来自其他子小部件的通知,我只能想到用另一个NotificationListener

NotificationListener(
  onNotification: (_)=> true,
  child: ListView.builder(
    scrollDirection: Axis.horizontal,
    itemBuilder: (ctx,index) => Container(width: 50,color: Colors.primaries[index%Colors.primaries.length],),
  ),
),

结果:

enter image description here

最后:

  • 我只处理 PageView 的左侧滚动
  • 为简单起见,我没有在拖动结束时实现 PageScrollPhysic(根据速度和页面位置计算)。