美文网首页iOS技术点iOS DeveloperiOS第三方库分析
APP常见的滑动导航实现:TYPagerController源码

APP常见的滑动导航实现:TYPagerController源码

作者: ZZZEoEv | 来源:发表于2016-09-28 23:57 被阅读1129次

    写在前面

    滑动导航的问题,主要是解决上方TabBar与下方ScrollView的联动问题。
    在上一篇文章中,我们详细分析了ScrollView构成。
    本篇我们就来看看作者是怎么处理联动问题的

    一、TYTabPagerController,TYTabButtonPagerController总体介绍

    TYTabPagerController在基类的基础上,主要做了两件事情:

    • 增加头部CollectionView
    • 增加滑动过程中的逻辑处理

    而TYTabButtonPagerController在TYTabPagerController的基础上,也做了两件事情:

    • 增加了Label Cell至CollectionView(头部tabBar)
    • 实现了 TYTabPagerControllerDelegate协议的部分方法

    二、TYTabPagerController详细分析

    先看一个效果图:



    重点看一下头部的tabBar,主要由两个部分组成:

    • 标签
    • UnderView

    标签部分,我们可以用Label+ScrollView的方式实现,也可以直接使用CollectionView,推荐使用后者(为我们封装好了很多现成的功能,下文会提到)。
    UnderView部分,根据Index和滑动比实时计算其frame就可以实现。
    下面我们看看作者具体是怎么写得。

    2.1 init

    一如既往,只是简单的配置了下数据:

    2.2 life Cycle

    这部分,主要是各部分视图初始化,大体过程:

    2.3 代理

    2.3.1 TYTabPagerControllerDelegate

    继承自基类中定义的TYPagerControllerDelegate,也是用来处理transition逻辑的:


    2.3.2 setDelegate

    在设置代理的时候,作者用一个struct记录了代理是否实现了相关方法,避免了后面冗余的检查代码,值得学习。

    2.3.3 collectionViewDelegate

    Paste_Image.png

    2.4 滑动逻辑处理(重点)

    在上一篇中,我们已经讨论过了滑动逻辑处理的总体计算流程:

    TYTabPagerController主要实现了上图中提到的,子类、代理实现的处理index以及progress的方法

    2.4.1 处理Index的方法

    作用:在本方法中,调用在一次滑动过程中只需要处理一次的方法。
    举例:通知delegate刚刚完成一次transition,或者调整collectionView的offset使选中Item居中显示



    看看上面的流程图,回忆一下基类中的流程(只有当index发生改变的时候,该处理方法才会被调用)。
    所以特别适合处理一次滑动只需要响应一次的事件,比如下图的选中Label自动居中的功能:

    该功能的实现,是collectionView为我们封装好的:


    注意上图我的注释,『如果可能的话』,什么情况下才会生效?
    起始这个功能的实现,本质上就是对CollectionView Offset的修改,而Offset是有范围的,很明显不能为了居中显示指定的Item,将Offset超范围修改。
    所以,在左侧和右侧的Item被选中的时候,CollectionView的offset是不会被修改的。


    2.4.2 处理Progress的方法

    作用:在此方法中调用需要实时处理的方法
    举例:修改underLineView的Frame,修改Label的transform、color等一切需要跟Progress实时互动的事件

    在该方法中,调用了delegate处理progress相关的方法;
    还调用了另一个核心方法:setUnderLineFrame

    setUnderLineFrame

    作用:实时设定underLineViewFrame
    实现:根据toIndex、FromIndex和滑动比实时计算UnderViewFrame
    难点:不同风格对应不同的计算公式


    上面这一坨代码,是不是看起来很晕?别急,其实拆开来看,并不难,我们下面一一进行分析:
    先指明一下作者设定的一个的变量:


    这个属性的作用呢,就是指定underLineView的首尾距离与Cell首尾的距离的,特此说明一下方便理解。

    一般风格TYPagerBarStyleProgressView

    我们从最简单也是最常用的部分开始介绍:



    为了便于分析,我们先假设underLineView的width与cell的width一致。
    先分析originX:

    • 初始值:fromCell.frame.origin.x
    • 目标值:toCell.frame.origin.x
    • 变化值:(toCell.frame.origin.x - fromCell.frame.origin.x)

    将变化值与我们的progress挂钩,就可以得到动态变化的width了。

    按照我们的分析来看一下源代码。

    图中标号为1的部分,toCellFrame.origin.x + targetUnderLineViewEdgeToCell,其实就是我们上面提到的目标值。
    图中标号为2的部分,就是我们的初始值。
    两者相减 X progress 就是我们需要的与Progress挂钩的动态变化值。
    再加上标号3,我们的初始值,就得到了frame.origin.x的计算式。

    再看width部分,一样的分析方法:

    • 初始值: fromCell.frame.width
    • 目标值: toCell.frame.width
    • 变化值: (toCell.frame.width - fromCell.frame.width)
    • 计算表达式:fromeCell.frame.width + (toCell.frame.width - fromCell.frame.width) X progress

    原作者的表达式化简一下,会得到一样的式子。

    Bounce风格TYPagerBarStyleProgressBounceView

    Bounce风格的话,比常见的要麻烦一些,不过列计算表达式的方式还是一样的:

    • 初始值
    • 目标值
    • 变化值

    只要找出这三者,就可以列出符合要求的表达式。

    这个动画过渡,是以progress=0.5为分界,分成上下两个部分,我们先来看上半部分的动画:

    X坐标:

    • 初始值:fromCellFrame.origin.x + fromEdge
    • 目标值:同初始值
    • 变化值:0

    从动画中,我们也可以看到,这个阶段的originX一致保持初始值的状态。
    width:

    • 初始值: fromeCellFrame.width - 2*fromEdge
    • 目标值:初始值 + fromEdge + cellSpacing + toEdge + toCellFrame.width - 2 *toEdge
    • 变化值: 目标值 - 初始值 = fromEdge + cellSpacing + toEdge + toCellFrame.width - 2 *toEdge
    • 表达式: 初始值 + 变化值progress2(这里之所以x2,是因为progress的变化范围为[0,5],而我们需要的变化区间为[0,1])

    我们来看一下作者的源码:

    图标1处即为初始值,图标2处为变化值,最后变化值与2*progress相乘。

    小结

    分析方法就是这么简单,找出初始值、目标值、变化值,再确认我们的变化区间,就可以写出我们的目标表达式。
    其它情况的分析方法也一样,这里就不再赘述了,有兴趣的朋友可以自己推导一下。


    三、TYTabButtonPagerController分析

    这个类,是作者为我们写好的一个滑动导航控制器,基本能满足我们的日常需求。
    它主要是在TYTabPagerController的基础上,对一些细节进行了设置,总体没有什么难度,所以就不细讲了,感兴趣的同学可以自己看一下。
    核心逻辑处理部分就一处:

    与上一节的setUnderLineViewFrame同时进行,对Cell的颜色以及字体进行变换,代码很简单。

    四、总结

    至此,滑动导航控制器的第三方库分析已经完成了。
    TYPagerController基本能满足我们的日常需求,当我们有更进一步的需求的时候,也可以再进行定制。
    整体来说,代码的逻辑控制不错,要是变量名、方法名还有注释能更完善一些就更好了。
    读起来还是有些不顺畅,不过也算是给自己提个醒:
    『代码是写给人看的』

    相关文章

      网友评论

      • MasterY:默认值不好使啊。以前有个moveto。现在是scrollto。但是不好使啊
      • Luke_coder:哈哈,,动画那几个枚举定义的我也是一脸懵逼,半天没看懂,代码是写给人看的,强烈赞同

      本文标题:APP常见的滑动导航实现:TYPagerController源码

      本文链接:https://www.haomeiwen.com/subject/kxwhyttx.html