在分析SwipeRefreshLayout源码的时候发现该类实现了NestedScrollingParent和NestedScrollingChild两个接口,甚是好奇,于是结合了网上的资料,然后根据我个人的理解写下本章.
这个两个接口是为了更好解决事件冲突的.
在这里 nested scrolling 就翻译为嵌套滚动吧.
但是这和以前用过的dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent和requestDisallowInterceptTouchEvent有什么区别呢?其实我感觉NestedScrollingParent和NestedScrollingChild是辅助解决事件冲突出现的.在之前的事件拦截中,就算子View的ACTION_MOVE的事件返回false,父布局也是获取不了该事件的.
NestedScrollingChild接口的定义如下:
public interface NestedScrollingChild { public void setNestedScrollingEnabled(boolean enabled); public boolean isNestedScrollingEnabled(); public boolean startNestedScroll(int axes); public void stopNestedScroll(); public boolean hasNestedScrollingParent(); public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow); 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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
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 { public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes); public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes); public void onStopNestedScroll(View target); public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed); 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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
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(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
接着是子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(ViewCompat.SCROLL_AXIS_VERTICAL); break; case MotionEvent.ACTION_MOVE: 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: stopNestedScroll(); break; default: break; } return true; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
布局文件如下:
<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的分析就到这里了.
0 0