学习Android NestedScroll
NestedScrollingChildHelper
这是一个用于实现子视图嵌套滚动的辅助类,并提供对Android 5.0之前版本的前兼容。
View要作为嵌套滚动中的Child,要在构造方法中实例化一个final的NestedScrollingChildHelper对象。该View中有一系列方法签名(即方法名和参数列表)和此类中相同的方法(这些方法实际来自于View实现的NestedScrollingChild接口),通过委托模式(delegate),这些方法的实际实现被委派给helper对象来完成。这提供了一种标准的结构化策略,来实现嵌套滚动。
例如,下面是NestedScrollView中相关的代码:
public class NestedScrollView extends FrameLayout implements NestedScrollingParent,
NestedScrollingChild {
......
private final NestedScrollingParentHelper mParentHelper;
// 这里文档中特别强调需要final修饰,而且要在构造方法中实例化
private final NestedScrollingChildHelper mChildHelper;
public NestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
......
mParentHelper = new NestedScrollingParentHelper(this);
mChildHelper = new NestedScrollingChildHelper(this);
......
}
// 下面9个方法来自于NestedScrollingChild接口,注意他们只是简单调用了mChildHelper中同名同参数列表的方法。
@Override
public void setNestedScrollingEnabled(boolean 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);
}
......
}
使用嵌套滚动功能的视图,应该始终使用ViewCompat, ViewGroupCompat 或者 ViewParentCompat中相关的兼容性静态方法。这保证了和Android 5.0之后的嵌套滚动视图之间互操作的正确性。
下面来具体的看这九个方法在NestedScrollingChildHelper类中的实现:
使能或禁止Child的嵌套滚动。
public void setNestedScrollingEnabled(boolean enabled) {
// 如果处于使能状态,有可能正在滚动,需要先停止。
if (mIsNestedScrollingEnabled) {
// 相当于调用View.stopNestedScroll()。
// 这个方法如果View正在嵌套滚动,会停止嵌套滚动,反之无影响。
// 注意这里实际还是会调用到NestedScrollingChildHelper.stopNestedScroll()。
ViewCompat.stopNestedScroll(mView);
}
// 这个标志位代表能否嵌套滚动。
mIsNestedScrollingEnabled = enabled;
}
返回是否可以嵌套滚动。
// 如果这里返回true,说明相应的子视图可以嵌套滚动。
// 那么helper类会负责将滚动操作过程中的相关数据传递给相关联的nested scrolling parent。
public boolean isNestedScrollingEnabled() {
return mIsNestedScrollingEnabled;
}
检查是否有关联的父视图,来接受嵌套滚动过程中的事件。
// 注意这里的mNestedScrollingParent初始化时是null,
// 是在下面的startNestedScroll(int axes)方法中找到的。
public boolean hasNestedScrollingParent() {
return mNestedScrollingParent != null;
}
开始一个新的嵌套滚动。
// 参数axes代表滚动轴,取ViewCompat#SCROLL_AXIS_HORIZONTAL and/or ViewCompat#SCROLL_AXIS_VERTICAL。
// 如果找到了嵌套滚动的parent view,并且对于当前手势使能了嵌套滚动,返回true。
public boolean startNestedScroll(int axes) {
if (hasNestedScrollingParent()) {
// 已经在嵌套滚动过程中。
return true;
}
// 嵌套滚动功能使能情况下才能开始。
if (isNestedScrollingEnabled()) {
ViewParent p = mView.getParent();
View child = mView;
// 依次找父视图,直到找到第一个接受嵌套滚动的父视图。
while (p != null) {
// 实际调用的是NestedScrollingParent中的
// onStartNestedScroll(View child, View target, int nestedScrollAxes)方法。
// 返回父视图是否接受此嵌套滚动操作。
if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {
mNestedScrollingParent = p;
// 这里实际会调用NestedScrollingParentHelper.onNestedScrollAccepted(View child, View target, int axes)方法。
ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);
return true;
}
if (p instanceof View) {
child = (View) p;
}
p = p.getParent();
}
}
return false;
}
停止嵌套滚动
public void stopNestedScroll() {
if (mNestedScrollingParent != null) {
// 实际调用的是NestedScrollingParentHelper.onStopNestedScroll(View target)。
ViewParentCompat.onStopNestedScroll(mNestedScrollingParent, mView);
mNestedScrollingParent = null;
}
}
将嵌套滚动过程中的一步分发给当前的nested scrolling parent。
// 返回true代表该事件被分发(即父视图消费任意的嵌套滚动事件),反之则是无法被分发。
public boolean dispatchNestedScroll(
int dxConsumed, // 滚动中被此view消费的水平距离
int dyConsumed, // 滚动中被此view消费的垂直距离
int dxUnconsumed, // 滚动中未被此view消费的水平距离
int dyUnconsumed, // 滚动中未被此view消费的垂直距离
int[] offsetInWindow // 滚动前后此view的坐标偏移量
) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
int startX = 0;
int startY = 0;
if (offsetInWindow != null) {
mView.getLocationInWindow(offsetInWindow);
startX = offsetInWindow[0];
startY = offsetInWindow[1];
} // 此方法来自NestedScrollingParent.onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed);
// 具体实现由父视图完成。
ViewParentCompat.onNestedScroll(mNestedScrollingParent, mView, dxConsumed,
dyConsumed, dxUnconsumed, dyUnconsumed); if (offsetInWindow != null) {
mView.getLocationInWindow(offsetInWindow);
// 偏移量是滚动后的位置减滚动前的位置
offsetInWindow[0] -= startX;
offsetInWindow[1] -= startY;
}
return true;
} else if (offsetInWindow != null) {
// No motion, no dispatch. Keep offsetInWindow up to date.
offsetInWindow[0] = 0;
offsetInWindow[1] = 0;
}
}
return false;
}
学习Android NestedScroll的更多相关文章
- 想学习Android开发
最近被别人说知识面窄,心里受伤了.准备学学Android开发,如果能在手机里运行自己写的app,那是多么high ~~~ Android开发需要看什么资料呢? 说明:本人一直从事windows下的C+ ...
- 从零开始学习Android(一)Android环境的搭建
好久没有开始写博客了,最近开始学习Android,所以想把学习的笔记都一一记录下来.一来是方便自己以后资料的查询,其次也是给Android新手朋友进行学习使用,再次也希 望得到高手的指点.废话少说,我 ...
- 《IT蓝豹》吹雪花demo,学习android传感器
吹雪花demo,学习android传感器 吹雪花demo,学习android传感器,嘴巴对着手机底部吹一下就会出现飘着雪花效果. 算是学习android传感器效果.本例子主要是通过android.me ...
- 一起来学习Android自定义控件1
概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...
- 10个很棒的学习Android 开发的网站(转)
看到江湖旅人 写的<10个很棒的学习iOS开发的网站 - 简书>,所以就忍不住写Android 啦,也希望对大家有帮助.我推荐的网站,都是我在学习Android 开发过程中发现的好网站,给 ...
- 学习android学习必备的java基础知识--四大内部类
学习android必备的java基础知识--四大内部类 今天学习android课程,因为我的主专业是JAVA,但是兴趣班却有这其他专业的同学,学习android 需要具备一些java的基础知识,因此就 ...
- 深入学习Android有关网络连接的内容
基于实际项目中碰到的些许问题,开始重新深入学习Android网络连接有关知识. Android的4.1.2版本的AndroidHttpClient模块setSoTimeout之后实际超时时间和设置的时 ...
- android学习——android架构
android架构:在了解全局的情况下进行细致化的分析才能更有效的学习android的运行原理,才能更深刻的理解android开发: 1.架构图直观 2.架构详解 2.1.Linux Kernel 2 ...
- 跟Google学习Android开发-起始篇-构建你的第一个应用程序(4)
说明:此系列教程翻译自Google Android开发者官网的Training教程,利用Chome浏览器的自动翻译功能作初译,然后在一些语句不顺或容易造成误解的地方作局部修正.方便英文不好的开发者查看 ...
随机推荐
- Mysql中存储方式的区别
MySQL的表属性有:MyISAM 和 InnoDB 2种存储方式: MyISAM 不支持事务回滚 InnoDB 支持事务回滚 可以用 show create table tablename 命令看表 ...
- box flex 弹性盒模型(转载)
css3引入了新的盒模型——弹性盒模型,该模型决定一个盒子在其他盒子中的分布方式以及如何处理可用的空间.这与XUL(火狐使用的用户交互语言)相似,其它语言也使用相同的盒模型,如XAML .GladeX ...
- 在ubuntu14.14 安装php扩展扩展出现的问题
我是在ubuntu14.14 安装的 lnmp. 部分扩展.均已安装好,但是我用apt-get 方式安装 redis和curl扩展时,我的配置都设置但是从phpinfo里面看没有响应的配置项. 于是我 ...
- PHP获取操作系统、IP、地理位置、浏览器、ISP等信息_PHP类代码
PHP语言.浏览器.操作系统.IP.地理位置.ISP,本PHP类里面有以下几种方法,同时也是用法说明: <?php class class_guest_info{ function GetLan ...
- Chrome下的语音控制框架MyVoix.js使用篇(四)
在上一篇博文中,我为大家介绍了myvoix.js中的smart learning模块,以及何如使用该功能.(myvoix.js的源码地址会在每一篇文章末尾放出) 文本将拓展 Chrome下的语音控制框 ...
- MYSQL正式环境主从复制(不锁表,不停服务)
参考URL: http://rfyiamcool.blog.51cto.com/1030776/1016636/ 原因源于其实以前环境是有MYSQL主从复制的,且最开始主从复制之间是OK的. 但由于日 ...
- 更改Altium中PCB大小/精确确定板子尺寸
使用原理图生成PCB后,Altium Designer会根据原理图大小自动生成一块黑色区域,还有一个在禁止布线层的方框,还有两段标注板子大小的线.下面说一下如何更改黑色区域的大小,还有如何精确确定板子 ...
- XAMPP的Apache服务器无法正常启动解决方案
XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建 XAMPP 软件站集成软件包.介绍什么的,参见百度百科http://baike.baidu.com/link?url=-UE ...
- vector,list和deque区别
stl提供了三个最基本的容器:vector,list,deque. vector和built-in数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随即存取,即[]操作符,但由 ...
- Java基础加强学习笔记(二)
一.反射的基础Class类 1.如何得到各个字节码对应的实例对象 (1)类名.class,例如 System.class (2)对象.getClass(),例如 new Data().getClass ...