Android中的NestedScrollingParent和NestedScrollingChild分析
来源:互联网 发布:学校网络整合营销策划 编辑:程序博客网 时间:2024/05/22 04:41
在分析SwipeRefreshLayout源码的时候发现该类实现了NestedScrollingParent和NestedScrollingChild两个接口,甚是好奇,于是结合了网上的资料,然后根据我个人的理解写下本章.
这个两个接口是为了更好解决事件冲突的.
在这里 nested scrolling 就翻译为嵌套滚动吧.
但是这和以前用过的dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent和requestDisallowInterceptTouchEvent有什么区别呢?其实我感觉NestedScrollingParent和NestedScrollingChild是辅助解决事件冲突出现的.在之前的事件拦截中,就算子View的ACTION_MOVE的事件返回false,父布局也是获取不了该事件的.
NestedScrollingChild接口的定义如下:
public interface NestedScrollingChild { // 参数enabled:true表示view使用嵌套滚动,false表示禁用. public void setNestedScrollingEnabled(boolean enabled); public boolean isNestedScrollingEnabled(); // 参数axes:表示滚动的方向如:ViewCompat.SCROLL_AXIS_VERTICAL(垂直方向滚动)和 // ViewCompat.SCROLL_AXIS_HORIZONTAL(水平方向滚动) // 返回值:true表示本次滚动支持嵌套滚动,false不支持 public boolean startNestedScroll(int axes); public void stopNestedScroll(); public boolean hasNestedScrollingParent(); // 参数dxConsumed: 表示view消费了x方向的距离长度 // 参数dyConsumed: 表示view消费了y方向的距离长度 // 参数dxUnconsumed: 表示滚动产生的x滚动距离还剩下多少没有消费 // 参数dyUnconsumed: 表示滚动产生的y滚动距离还剩下多少没有消费 // 参数offsetInWindow: 表示剩下的距离dxUnconsumed和dyUnconsumed使得view在父布局中的位置偏移了多少 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow); // 参数dx: 表示view本次x方向的滚动的总距离长度 // 参数dy: 表示view本次y方向的滚动的总距离长度 // 参数consumed: 表示父布局消费的距离,consumed[0]表示x方向,consumed[1]表示y方向 // 参数offsetInWindow: 表示剩下的距离dxUnconsumed和dyUnconsumed使得view在父布局中的位置偏移了多少 public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow); // 这个是滑动的就不详细分析了 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed); public boolean dispatchNestedPreFling(float velocityX, float velocityY);}
1,setNestedScrollingEnabled 实现该结构的View要调用setNestedScrollingEnabled(true)才可以使用嵌套滚动.
2,isNestedScrollingEnabled判断当前view能否使用嵌套滚动.
3,startNestedScroll和stopNestedScroll.是配对使用的.startNestedScroll表示view开始滚动了,一般是在ACTION_DOWN中调用,如果返回true则表示父布局支持嵌套滚动.在事件结束比如ACTION_UP或者ACTION_CANCLE中调用stopNestedScroll,告诉父布局滚动结束.
4,dispatchNestedScroll,把view消费滚动距离之后,把剩下的滑动距离再次传给父布局.
5,dispatchNestedPreScroll,在view消费滚动距离之前把总得滑动距离传给父布局.
6,dispatchNestedFling和dispatchNestedPreFling就是view传递滑动的信息给父布局的.
NestedScrollingParent接口的定义如下:
public interface NestedScrollingParent { // 参数child:ViewParent包含触发嵌套滚动的view的对象 // 参数target:触发嵌套滚动的view (在这里如果不涉及多层嵌套的话,child和target)是相同的 // 参数nestedScrollAxes:就是嵌套滚动的滚动方向了. public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes); public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes); public void onStopNestedScroll(View target); // 参数target:同上 // 参数dxConsumed:表示target已经消费的x方向的距离 // 参数dyConsumed:表示target已经消费的x方向的距离 // 参数dxUnconsumed:表示x方向剩下的滑动距离 // 参数dyUnconsumed:表示y方向剩下的滑动距离 public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed); // 参数dx:表示target本次滚动产生的x方向的滚动总距离 // 参数dy:表示target本次滚动产生的y方向的滚动总距离 // 参数consumed:表示父布局要消费的滚动距离,consumed[0]和consumed[1]分别表示父布局在x和y方向上消费的距离. public void onNestedPreScroll(View target, int dx, int dy, int[] consumed); public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed); public boolean onNestedPreFling(View target, float velocityX, float velocityY); public int getNestedScrollAxes();}
1,onStartNestedScroll.当子view的调用NestedScrollingChild的方法startNestedScroll时,会调用该方法.
2,onNestedScrollAccepted.如果onStartNestedScroll方法返回的是true的话,那么紧接着就会调用该方法.它是让嵌套滚动在开始滚动之前,让布局容器(viewGroup)或者它的父类执行一些配置的初始化的.下面是原文:
(It offers an opportunity for the view and its superclasses to perform initial configuration for the nested scroll.)
3,onStopNestedScroll停止滚动了,当子view调用stopNestedScroll时会调用该方法.
4,onNestedScroll,当子view调用dispatchNestedScroll方法时,会调用该方法.
5,onNestedPreScroll,当子view调用dispatchNestedPreScroll方法是,会调用该方法.
6,dispatchNestedFling和dispatchNestedPreFling对应的就是滑动了.
下面给出基本的例子,首先是父布局的代码:
package com.yluo.testnestscrolling;import android.annotation.SuppressLint;import android.content.Context;import android.support.v4.view.NestedScrollingParent;import android.support.v4.view.NestedScrollingParentHelper;import android.support.v4.view.ViewCompat;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.widget.FrameLayout;@SuppressLint("NewApi") public class NestScrollingLayout extends FrameLayout implements NestedScrollingParent{ private static final String TAG = "NestScrollingLayout"; private NestedScrollingParentHelper mParentHelper; public NestScrollingLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public NestScrollingLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public NestScrollingLayout(Context context) { super(context); init(); } @SuppressLint("NewApi") private void init() { mParentHelper = new NestedScrollingParentHelper(this); } @Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { Log.d(TAG, "child==target:" + (child == target)); Log.d(TAG, "----父布局onStartNestedScroll----------------"); return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; } @SuppressLint("NewApi") @Override public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { Log.d(TAG, "----父布局onNestedScrollAccepted---------------"); mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes); } @Override public void onStopNestedScroll(View target) { Log.d(TAG, "----父布局onStopNestedScroll----------------"); mParentHelper.onStopNestedScroll(target); } @Override public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { Log.d(TAG, "----父布局onNestedScroll----------------"); } @Override public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { scrollBy(0, -dy); consumed[0] = 0; consumed[1] = 10; // 把消费的距离放进去 Log.d(TAG, "----父布局onNestedPreScroll----------------"); } @Override public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { Log.d(TAG, "----父布局onNestedFling----------------"); return true; } @Override public boolean onNestedPreFling(View target, float velocityX, float velocityY) { Log.d(TAG, "----父布局onNestedPreFling----------------"); return true; } @Override public int getNestedScrollAxes() { Log.d(TAG, "----父布局getNestedScrollAxes----------------"); return mParentHelper.getNestedScrollAxes(); } }
接着是子View的代码:
package com.yluo.testnestscrolling;import android.content.Context;import android.support.v4.view.NestedScrollingChild;import android.support.v4.view.NestedScrollingChildHelper;import android.support.v4.view.ViewCompat;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;public class NestScrollingView extends View implements NestedScrollingChild{ private static final String TAG = "NestScrollingView"; private NestedScrollingChildHelper mChildHelper; private int[] mConsumed = new int[2]; private int[] mOffset = new int[2]; public NestScrollingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public NestScrollingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public NestScrollingView(Context context) { super(context); init(); } private void init() { mChildHelper = new NestedScrollingChildHelper(this); setNestedScrollingEnabled(true); } @Override public void setNestedScrollingEnabled(boolean enabled) { mChildHelper.setNestedScrollingEnabled(enabled); } @Override public boolean isNestedScrollingEnabled() { return mChildHelper.isNestedScrollingEnabled(); } @Override public boolean startNestedScroll(int axes) { Log.d(TAG, "-----------子View开始滚动---------------"); return mChildHelper.startNestedScroll(axes); } @Override public void stopNestedScroll() { Log.d(TAG, "-----------子View停止滚动---------------"); mChildHelper.stopNestedScroll(); } @Override public boolean hasNestedScrollingParent() { return mChildHelper.hasNestedScrollingParent(); } @Override public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { Log.d(TAG, "-----------子View把剩余的滚动距离传给父布局---------------"); return mChildHelper.dispatchNestedScroll(dxConsumed,dyConsumed, dxUnconsumed,dyUnconsumed,offsetInWindow); } @Override public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { Log.d(TAG, "-----------子View把总的滚动距离传给父布局---------------"); 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); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 按下事件调用startNestedScroll startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL); break; case MotionEvent.ACTION_MOVE: // 移动事件调用startNestedScroll dispatchNestedPreScroll(0,20,mConsumed,mOffset); // 输出一下偏移 Log.d(TAG, "offset--x:" + mOffset[0] + ",offset--y:" + mOffset[1]); dispatchNestedScroll(50,50,50,50,mOffset); break; case MotionEvent.ACTION_UP: // 弹起事件调用startNestedScroll stopNestedScroll(); break; default: break; } return true; }}
布局文件如下:
<com.yluo.testnestscrolling.NestScrollingLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.yluo.testnestscrolling.NestScrollingView android:layout_marginTop="100dp" android:layout_width="match_parent" android:layout_height="100dp" android:background="@android:color/holo_green_dark"> </com.yluo.testnestscrolling.NestScrollingView></com.yluo.testnestscrolling.NestScrollingLayout>
输出结果如下:
--------------子View开始滚动----------------------父布局onStartNestedScroll---------------- ----父布局onNestedScrollAccepted--------------------------子View把总的滚动距离传给父布局------------父布局onNestedPreScroll-------------------offset--x:0,offset--y:20-----------子View把剩余的滚动距离传给父布局------- ----父布局onNestedScroll---------------- -----------子View停止滚动--------------- ----父布局onStopNestedScroll----------------
输入的顺序跟之前我们分析的是一样的.好了NestedScrollingParent和NestedScrollingChild的分析就到这里了.
至于这两个接口的具体应用例子现在网上有很多,包括SDK也有.后面我在写Android自定义控件的时候也会讲解这两个接口的用法的.
好了就先到这里啦.
这是本文的测试例子的下载地址:
http://download.csdn.net/detail/x87648510/9573102
- Android中的NestedScrollingParent和NestedScrollingChild分析
- Android中的NestedScrollingParent和NestedScrollingChild分析
- NestedScrollingChild和NestedScrollingParent
- NestedScrollingParent 和NestedScrollingChild
- 从NestedScrollingChild、NestedScrollingParent源码分析嵌套滑动机制
- NestedScrollingParent, NestedScrollingChild 详解
- NestedScrollingParent, NestedScrollingChild 详解
- NestedScrollingParent, NestedScrollingChild 详解
- NestedScrollingParent, NestedScrollingChild 详解
- Android-NestedScrollingParent, NestedScrollingChild父子View 间 的 嵌套滑动
- NestedScrollingChild NestedScrollingParent API的粗略中文解释
- 实现嵌套滑动——NestedScrollingParent与NestedScrollingChild接口及其实现
- NestedScrollingParent
- Android 自定义WebView 实现 NestedScrollingChild
- Android 自定义WebView 实现 NestedScrollingChild
- Android NestedScrolling,NestedScrollingParent,NestedScrollingParentHelper解析
- Android中NestedScrollingParent嵌套ListView
- Android嵌套滚动Demo-NestedScrollingChild实现
- 《java多线程编程核心技术》核心笔记(二)
- CentOS7安装GNOME可视化界面流程
- uvaLive 3401 Colored Cubes 暴力
- 在oracle 通过sql实现一元线性回归方程
- Oracle学习
- Android中的NestedScrollingParent和NestedScrollingChild分析
- Android--添加阴影效果--CardView的使用
- Tempter of the Bone
- Activity的4种启动模式
- 教学中控简介
- OpenGL 入门纪录--视口变换函数glViewPort函数用法
- arduino gps
- Android中性能分析之TraceView
- Android 跨进程内存泄露