Android 在发布
Lollipop
版本之后,为了更好的用户体验,Google为Android的滑动机制提供了NestedScrolling
特性
NestedScrolling
的特性可以体现在哪里呢?
比如你使用了Toolbar
,下面一个ScrollView
,向上滚动隐藏Toolbar
,向下滚动显示Toolbar
,这里在逻辑上就是一个NestedScrolling
—— 因为你在滚动整个Toolbar
在内的View的过程中,又嵌套
滚动了里面的ScrollView
。
效果如上图【别嫌弃我】
在这之前,我们知道Android
对Touch
事件的分发是有自己一套机制的。主要是有是三个函数:dispatchTouchEvent
、onInterceptTouchEvent
和onTouchEvent
。
这种分发机制有一个漏洞:
如果子view获得处理touch事件机会的时候,父view就再也没有机会去处理这个touch事件了,直到下一次手指再按下。
也就是说,我们在滑动子View的时候,如果子View对这个滑动事件不想要处理的时候,只能抛弃这个touch事件,而不会把这些传给父view去处理。
但是Google新的NestedScrolling
机制就很好的解决了这个问题。
我们看看如何实现这个NestedScrolling
,首先有几个类(接口)我们需要关注一下
NestedScrollingChild
NestedScrollingParent
NestedScrollingChildHelper
NestedScrollingParentHelper
以上四个类都在support-v4
包中提供,Lollipop的View默认实现了几种方法。
实现接口很简单,这边我暂时用到了NestedScrollingChild
系列的方法(因为Parent是support-design提供的CoordinatorLayout
)
@Override
public void setNestedScrollingEnabled(boolean enabled) {
super.setNestedScrollingEnabled(enabled);
mChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return mChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
对,简单的话你就这么实现就好了。
这些接口都是我们在需要的时候自己调用的。childHelper干了些什么事呢?,看一下startNestedScroll
方法
/**
* Start a new nested scroll for this view.
*
* <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
* method/{@link NestedScrollingChild} interface method with the same signature to implement
* the standard policy.</p>
*
* @param axes Supported nested scroll axes.
* See {@link NestedScrollingChild#startNestedScroll(int)}.
* @return true if a cooperating parent view was found and nested scrolling started successfully
*/
public boolean startNestedScroll(int axes) {
if (hasNestedScrollingParent()) {
// Already in progress
return true;
}
if (isNestedScrollingEnabled()) {
ViewParent p = mView.getParent();
View child = mView;
while (p != null) {
if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {
mNestedScrollingParent = p;
ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);
return true;
}
if (p instanceof View) {
child = (View) p;
}
p = p.getParent();
}
}
return false;
}
可以看到这里是帮你实现一些跟NestedScrollingParent
交互的一些方法。ViewParentCompat
是一个和父view交互的兼容类,它会判断api version,如果在Lollipop以上,就是用view自带的方法,否则判断是否实现了NestedScrollingParent
接口,去调用接口的方法。
那么具体我们怎么使用这一套机制呢?比如子View这时候我需要通知父view告诉它我有一个嵌套的touch事件需要我们共同处理。那么针对一个只包含scroll交互,它整个工作流是这样的:
一、startNestedScroll
首先子view需要开启整个流程(内部主要是找到合适的能接受nestedScroll的parent),通知父View,我要和你配合处理TouchEvent
二、dispatchNestedPreScroll
在子View的onInterceptTouchEvent
或者onTouch
中(一般在MontionEvent.ACTION_MOVE事件里),调用该方法通知父View滑动的距离。该方法的第三第四个参数返回父view消费掉的scroll长度和子View的窗体偏移量。如果这个scroll没有被消费完,则子view进行处理剩下的一些距离,由于窗体进行了移动,如果你记录了手指最后的位置,需要根据第四个参数offsetInWindow
计算偏移量,才能保证下一次的touch事件的计算是正确的。
如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。
这个函数一般在子view处理scroll前调用。
三、dispatchNestedScroll
向父view汇报滚动情况,包括子view消费的部分和子view没有消费的部分。
如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。
这个函数一般在子view处理scroll后调用。
四、stopNestedScroll
结束整个流程。
整个对应流程是这样
startNestedScroll | onStartNestedScroll、onNestedScrollAccepted |
dispatchNestedPreScroll | onNestedPreScroll |
dispatchNestedScroll | onNestedScroll |
stopNestedScroll | onStopNestedScroll |
一般是子view发起调用,父view接受回调。
我们最需要关注的是dispatchNestedPreScroll
中的consumed
参数。
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) ;
它是一个int
型的数组,长度为2,第一个元素是父view消费的x
方向的滚动距离;第二个元素是父view消费的y
方向的滚动距离,如果这两个值不为0,则子view需要对滚动的量进行一些修正。正因为有了这个参数,使得我们处理滚动事件的时候,思路更加清晰,不会像以前一样被一堆的滚动参数搞混。
对NestedScroll的介绍暂时到这里,下一次将讲一下CoordinatorLayout
的使用(其中让人较难理解的Behavior对象),以及在SegmentFault Android客户端
中的实践。谢谢支持。
相关推荐
ListView下拉刷新 ListView下拉刷新ListView下拉刷新ListView下拉刷新
仿QQ下拉刷新 实现原理比较简单,可以直接运行看到效果
iScroll 5下拉刷新。 iScroll 5 更新之后的pull-to-refresh的demo没了,无奈,google下一个国外程序员写的上下拉刷新,自己精简了下,只保留了下拉刷新。
仿网易新闻客户端下拉刷新 实现原理比较简单,可以直接运行看到效果
微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab切换 (源码)微信小程序 下拉刷新,tab...
下拉刷新 上拉加载 上拉加载 底部点击加载 下拉刷新+上拉加载 下拉刷新+上拉加载 使用requirejs 下拉刷新+上拉加载 自定义dom 下拉刷新+上拉加载 固定头部 下拉刷新+上拉加载 tab一个实例 下拉刷新+上拉加载...
微信小程序scroll-view下拉刷新(附带下拉刷新效果) 使用说明 https://blog.csdn.net/u012308481/article/details/102619511
SwipeRefreshLayout和腾讯的X5内核的WebView相结合的下拉刷新,亲测华为荣耀android6.0 测试通过,由于百度某些页面单独处理过,开启了滚动条,否则下拉和下拉刷新冲突..2016年9月7日19:40:50
使用EGOTableViewPullRefresh开源项目在IOS中实现UITableView的下拉刷新功能,对源码进行了一些改动,支持中英文显示,刷新时间格式也做了修改
目前已经实现了四种下拉刷新效果: 新浪微博下拉刷新风格(可设置各种状态是的文本,可设置整个刷新头部的背景) 慕课网下拉刷新风格(可设置其中的 logo 和颜色成自己公司的风格,可设置整个刷新头部的背景) 美团...
强大的Android下拉刷新框支持下拉刷新、上拉加载、二级刷新、越界回弹、越界拖动,具有极强的扩展性,并集成了几十种炫酷的Header和 Footer。 支持横向刷新 支持多点触摸 支持淘宝二楼和二级刷新 支持嵌套多层的视图...
模仿抖音下拉刷新方式,模仿抖音下拉刷新方式,模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新方式模仿抖音下拉刷新...
Android自带下拉刷新的代码例子。用于演示Android原生控件SwipeRefreshLayout下拉刷新布局的功能与用法。
将开源项目PullToRefresh中的ScrollView下拉刷新提取出来了,可直接集成到项目中。
下拉刷新与加载 自定义控件下拉刷新与加载 自定义控件下拉刷新与加载 自定义控件下拉刷新与加载 自定义控件下拉刷新与加载 自定义控件下拉刷新与加载 自定义控件
Android 开源的下拉刷新 Eclipse版本 直接可以用。
最简单的下拉刷新 什么都不用改 直接在listview外面加一个头就行 布局 代码 都不用改 另外为了节约流量没有传包 自己加一下jar包就能运行了
自定义listview下拉刷新上拉加载更多以及与google官方的下拉刷新结合使用
android下拉刷新demo eclipse版本。下拉刷新特效围绕actionbar
自动、定时下拉刷新手机屏幕,用于某些软件自动下拉刷新数据