iPhone X 面市后,其异形屏给交互设计提供了更多想象的空间。在 Twitter 上,这位推友就针对刘海设计了列表环绕刘海滚动的效果。
最近在 codepen 上看到已经有人实现了这个 demo:https://codepen.io/davvidbaker/pen/KXgPyG,本文将图文结合分析一下实现这个效果的逻辑。
DOM 结构
DOM 结构比较简单,主要包括列表 ul
,其滚动容器为 class="inner"
的 DIV;刘海是 class="notch"
的 DIV。
滚动逻辑
为了实现列表环绕刘海滚动,需要在滚动事件中,计算处理每一行列表 X 轴方向的位置移动。
如上图列表向下滚动,上方的列表需要向右位移 notch
宽度;对应的,下方的列表需要向左位移 notch
宽度。我们需要对移动进行相应的计算处理,使位移线性变化,从而在滚动时,环绕效果自然。
distFromTop
和 distFromBottom
列表在上下滚动过程中分为两部分:
- 向下滚动:上方列表向右移动进入刘海区域,下方列表向左移动离开刘海区域
- 向上滚动:上方列表向左移动离开刘海区域,下方列表向右移动进入刘海区域
这两部分刚好是相对应的,此处我们只分析上方列表移动进入/离开刘海区域,即可以了解滚动过程中的逻辑处理。首先介绍两个变量:distFromTop
和 distFromBottom
Element.getBoundingClientRect()
方法返回元素的大小及其相对于视口的位置,返回值是一个DOMRect
对象。DOMRect
对象包含了一组用于描述边框的只读属性 —— left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的,如下图:
|
|
这两个变量表征当前这一行列表距离上下刘海边界的位置,在滚动过程中根据 distFromTop
和 distFromBottom
变量触发不同的位移逻辑。
位移逻辑
分析上方列表移动进入/离开刘海区域时,列表位移的逻辑。
1️⃣ 阈值:Threshold
在刘海边界上下 Threshold
区域定义为位移区域,列表进入这一区域即需要进行计算位移量,检测是否进入这一区域的逻辑判断为:
2️⃣ 计算位移量
考虑两个边界情况:
- 当
distFromTop
等于- Threshold
,即列表开始进入刘海区域
此时位移量为 0 - 当
distFromTop
等于+ Threshold
,即列表完全进入刘海区域
此时位移量为刘海宽度NotchWidth
这个变换过程可以通过线性插值来完成,根据 distFromTop
变量计算在 Y 轴方向的比例关系,从而得到 X 轴方向的位移量。
关于线性插值参考:维基百科:线性插值
在此处,我们可以简化理解,如下图
计算公式如下:
在我们分析的这个情形:上方列表向右移动进入刘海区域,对应的调用为:
其他情况,位移量计算分别为:
- 在刘海区域内滚动
判断条件:distFromTop > 0 && distFromBottom < - Threshold
位移量始终为:刘海宽度NotchWidth
- 下方列表移动进入/离开刘海区域
判断条件:Math.abs(distFromBottom) <= Threshold
位移量始终为:x = lerp(NotchWidth, 0, (distFromBottom + Threshold) / (Threshold * 2))
- 其他
位移量始终为:0
完整代码
最终实现效果:https://codepen.io/yingshandeng/pen/JrJRBR?editors=1010
|
|