![](https://s5-media.51cto.com/ost/pc/static/noavatar.gif)
ohos扩展包—— ScrollHelper
滚动逻辑重写帮助类ScrollHelper
由于在ohos中,我们无法重写系统控件的触摸事件,只能通过setTouchListener来设置一个回调,这意味着我们无法侵入到ohos系统控件原有的滚动处理逻辑内。因此我们如果需要实现NestedScrollingChild接口,就需要重写控件的滚动逻辑。
ScrollHelper类封装了一套比较通用的滚动处理逻辑,并且内部维护了NestedScrollingChildHelper实例对象,自定义控件只需要实现ScrollingView与NestedScrollingChild等接口,并转发NestedScrollingChild中的函数至ScrollHelper的同名函数即可重写滚动逻辑。
注意:ScrollHelper仅仅处理滚动相关的逻辑,比如事件分发、触摸事件处理、嵌套滚动,其主要作用是帮助现有的可滚动的组件实现嵌套滚动。如果想要实现滚动本身,可以借助ScrollApiHelper
使用
- 实现ViewGroup、ScrollingView与NestedScrollingChild接口
- 初始化ScrollHelper
3、设置setTouchEventListener,并转发ohos的onTouchEvent至ScrollHelper中
4、转发ViewGroup接口至ScrollHelper的同名函数中:
5、转发NestedScrollingChild至ScrollHelper的同名函数中:
6、实现ScrollView逻辑,具体含义可以参考该接口的注释。
滚动api帮助类 ScrollApiHelper
由于鸿蒙中普通控件与布局的scrollBy、scrollTo函数不生效,因此使用此类帮助控件滚动
使用
原理
通过将该控件的所有child通过setComponentPosition改变位置,达到整体滚动的效果。
- child的top:子控件的初始top + scrollY
- child的left:子控件的初始left + scrollX
scrollApiHelper会缓存所有child的初始位置信息,并于当前的滚动距离相加,计算得出child的新的top或者left并设置进去。
注意
由于是通过setComponentPosition来实现的滚动,因此获取child的top、left、right、bottom等会出现数值不是预期的情况,真实的值应该是:
- top: Component.getTop + ScrollApiHelper.getScrollY
- left: Component.getLeft + ScrollApiHelper.getScrollX
- right: Component.getRight + ScrollApiHelper.getScrollX
- bottom: Component.getBottom + ScrollApiHelper.getScrollY
关于onArrange
由于是使用setComponentPosition来实现滚动,而非控件内的scroll来实现,因此在控件发生重新布局后,滚动会跳到最顶部。这是因为onArrange会把所有子控件的位置还原。
如果我们自定义了控件,并且确定在滚动途中会发生重新布局,或者调用了postLayout或者invalidate函数,那么我们可以通过在onArrange内,将child的top或者left加上我们当前的滚动距离,就可以达到滚动不往顶部跳的目的。
但是这样会产生另外一个问题就是滚动值的计算会出现问题,因为所有child的初始top或者left已经发生了改变。这时我们需要为ScrollApiHelper设置一个偏移量,来中和初始top或者left的改变,并且重新缓存child的位置信息。
即在onArrange内:
- 将child的top或者left加上我们当前的滚动距离
- 为ScrollApiHelper设置一个偏移量,值为当前的滚动距离
- 重新缓存child的位置信息
以垂直方向滚动举例(不完整代码):
![](https://s5-media.51cto.com/ost/pc/static/noavatar.gif)