android tab pageview,[Flutter]从零开始实现一个嵌套滑动的PageView(一)

前言

首先呢,为什么会有PageView嵌套PageView这个需求……

我们来看下抖音的交互:

7455b6dcbd3f31987d2d1b83dbd23763.gif抖音交互

从图上不难分析出,首页里面放了2个tab,右边的菜单栏则是独立存在的一个页面

再加上嵌套滑动,所以实现方式就是,PageView里面再嵌套一个布局,首页那块无法就是在这个嵌套布局中加入一个TabBarView就好了嘛,菜单栏用状态管理来更新菜单内容,so easy~

然而事实证明我还是太年轻了……TabBarView其实就是PageView的拓展实现,然鹅,PageView是不支持嵌套滑动的……

解决方案

手势监听,给所有View加上动画,当划出菜单的时候,用动画方式移动底部的标签栏

NestedScrollerView 加上PageView 的physics?

实现一个能支持嵌套滑动的PageView

当然,如果我采用第一种方案也就没这篇文章了,其中方案调研的血泪史不提也罢。

首先需要了解的知识(课前准备)

Flutter中,提到嵌套滑动,自然第一想到的就是NestedScrollView,所以如果想给PageView加上嵌套滑动机制,学习下NestedScrollView及其核心原理能给我们很大的帮助。

Scrollable.dart 中的ScrollerController,ScrollerPosition等,了解其用途、基本含义和使用方法(当然,这篇文章需要的没那么多,要想理解,只需要看下ScrollerController、ScrollerPosition即可,那些beginActivity、ScrollActivity什么的不明白也罢,这篇文章用不到,用ScrollPositionWithSingleContext复制黏贴过来的就行)。

万里长征第一步,让它嵌套滑动起来

做好课前准备之后,我们最简单的描述一下 NestedScrollView 的嵌套滑动步骤:

创建_NestedScrollCoordinator ,同时创建2个ScrollController,用于管理整体的CunstomScrollerView和内部primary的可滑动布局

通过 自定义的ScrollController ,返回自定义ScrollPosition,顺便将Delegate 具体实现交给 _NestedScrollCoordinator来实现。

delegate 通过具体的 applyUserOffset 方法来控制整个列表的内容,顺序是往上或者往左滑先滑外部,往下或往右滑先处理内部。

如果实现PageView的嵌套滑动,也可以采取这个思路。

一些小小坑

PageView本身是不支持primary的,所以如果想像NestedScrollerView那样不需要给child传入特定controller,直接用即可的话,就需要实现一个支持Primary的PageView;

PageView是不会保活的,所以如果拉到主PageView的第二页,包含子PageView的第一页就会dispose,因此丢失滑动状态,再拉回来的时候自然展示的是第一页,而不是嵌套滑动之后的最大页。所以这块需要保活处理一下下

核心代码

1class _ChildPagePosition extends ScrollPosition

2    implements PageMetrics, ScrollActivityDelegate{

3  _ChildPagePosition({

4    this.parentController,

5    ScrollPhysics physics,

6    ScrollContext context,

7    this.initialPage = 0,

8    bool keepPage = true,

9    double viewportFraction = 1.0,

10    double initialPixels = 0.0,

11    ScrollPosition oldPosition,

12  })

13      : assert(initialPage != null),

14        assert(keepPage != null),

15        assert(viewportFraction != null),

16        assert(viewportFraction > 0.0),

17        _viewportFraction = viewportFraction,

18        _pageToUseOnStartup = initialPage.toDouble(),

19        super(

20        physics: physics,

21        context: context,

22        keepScrollOffset: keepPage,

23        oldPosition: oldPosition,

24      ) {

25    // If oldPosition is not null, the superclass will first call absorb(),

26    // which may set _pixels and _activity.

27    if (pixels == null && initialPixels != null)

28      correctPixels(initialPixels);

29    if (activity == null)

30      goIdle();

31    assert(activity != null);

32  }

33

34  /// 中间一大堆无关方法略过

35

36  @override

37  void applyUserOffset(double delta) {

38    updateUserScrollDirection(

39        delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);

40    final double newPixels = pixels -

41        physics.applyPhysicsToUserOffset(this, delta);

42    final double overScroll = physics.applyBoundaryConditions(this, newPixels);

43    if (overScroll == 0) {

44      setPixels(newPixels);

45    } else {

46      if(parentController!=null){

47        if(parentController.position is _PagePosition){

48          (parentController.position as _PagePosition).applyClampedDragUpdate(-overScroll);

49        }

50      }

51      print("触发上级滑动");

52    }

53  }

54}

复制代码

Look Look 效果

bfee34f3dee963c7af5edfae8e88b137.gifNestedPageView 1.0

后记

当然,支持嵌套滑动仅仅只是开始……

如图所示,目前仅仅嵌套滑动了而已,松开手之后的physics效果,拉到一半再拉回去等操作也没特殊处理,嘛,不过这是以后的事了……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值