SwipeRefreshLayout 是在Android Support Library, revision 19.1.0加入到support v4库中的一个下拉刷新控件,关于android的下拉刷新框架如今有好多,以前用过XListView,如今工作中基本上无需用到下拉刷新的功能。

废话不多说了。这里来记录一下android自带的刷新控件SwipeRefreshLayout的使用,借此顺便来熟悉一下android 在Lollipop版本号推出的嵌套滑动机制(NestedScrolling)。

首先来看SwipeRefreshLayout的使用,使用非常easy。看一下布局文件

<?xml version="1.0" encoding="utf-8"?

> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/swiperefresh" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="cj.com.recyclerviewdemo.RecyclerViewActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> </android.support.v4.widget.SwipeRefreshLayout>

注意SwipeRefreshLayout仅仅能有一个直接的子View。这里用了RecyclerView,由于前面刚刚讲过它。其有用啥子View都行。仅仅要你想通过竖直方向的滑动来刷新该View的显示内容。

关于SwipeRefreshLayout的一些API:

swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swiperefresh);mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE);//swipeRefreshLayout.setSize(SwipeRefreshLayout.DEFAULT);//默认  设置进度圈的大小,仅仅有两个值:DEFAULT、LARGE//swipeRefreshLayout.setProgressBackgroundColorSchemeColor(Color.RED);//设置进度圈的背景色。//swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimaryDark,R.color.colorPrimary,R.color.cardViewcolor);//设置进度动画的颜色.....swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {Log.d("test","onRefresh");datas.add(0,new Contact("xiaochen","10086"));handler.postDelayed(new Runnable() {@Overridepublic void run() {mAdapter.notifyDataSetChanged();swipeRefreshLayout.setRefreshing(false);//设置刷新状态 false停止刷新}},5000);}});

这里还是依据前文的demo来写的,就刷新的时候,在第一个位置加入一条数据,咱看效果:

SwipeRefreshLayout的使用没啥好讲的。比較简单。

咱再一张效果图:

注意上面我就传一个事件流,即一个down事件,N个Move事件,一个up事件,然而我们能够发现Move事件的时候被SwipeRefreshLayout(出现进度圈)和RecyclerView(向上滚动)都处理了,记得前面源代码分析Android触摸事件处理机制一文我们分析过,android默认的触摸事件处理框架一个事件流仅仅能被一个View处理,当然通过一些手段还是能够做到一个事件流同一时候被几个View处理,显然SwipeRefreshLayout和RecyclerView对触摸事件的处理流程做了一定处理。

所以咱来看看SwipeRefreshLayout和RecyclerView的 源代码,这里就不是去分析它们源代码看它们怎么处理事件。仅仅是引出嵌套滑动的机制:

public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingParent,NestedScrollingChild {
 private final NestedScrollingParentHelper mNestedScrollingParentHelper;private final NestedScrollingChildHelper mNestedScrollingChildHelper;

SwipeRefreshLayout实现了NestedScrollingParent接口,同一时候它也有一个成员变量是NestedScrollingParentHelper类型

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {
 private NestedScrollingChildHelper mScrollingChildHelper;

RecyclerView实现了NestedScrollingChild接口,同一时候它也有一个成员变量是NestedScrollingChildHelper类型
发现了四个新的对象NestedScrollingParent,NestedScrollingChild,NestedScrollingChildHelper,NestedScrollingParentHelper。

前面说嵌套滑动机制主要由上面四个对象来实现的,SwipeRefreshLayout和RecyclerView之间就是利用嵌套滑动来实现下拉刷新的,大家有兴趣能够阅读源代码去分析。以下讲一下android这个嵌套滑动机制

Android 在公布 Lollipop版本号之后。为了更好的用户体验,Google为Android的滑动机制提供了NestedScrolling特性

理解嵌套滑动,须要理解以下几个类(接口):
NestedScrollingChild
NestedScrollingParent
NestedScrollingChildHelper
NestedScrollingParentHelper

以上四个类都在support-v4包(Android Support Library, revision 22.1.0加入的)中提供。Lollipop的View默认实现了几种方法。

先来看  NestedScrollingChild 接口,  顾名思义, 这个是子View 应该实现 的接口:

/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.support.v4.view;import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;/*** This interface should be implemented by {@link android.view.View View} subclasses that wish* to support dispatching nested scrolling operations to a cooperating parent* {@link android.view.ViewGroup ViewGroup}.** <p>Classes implementing this interface should create a final instance of a* {@link NestedScrollingChildHelper} as a field and delegate any View methods to the* <code>NestedScrollingChildHelper</code> methods of the same signature.</p>** <p>Views invoking nested scrolling functionality should always do so from the relevant* {@link ViewCompat}, {@link ViewGroupCompat} or {@link ViewParentCompat} compatibility* shim static methods. This ensures interoperability with nested scrolling views on Android* 5.0 Lollipop and newer.</p>*/
public interface NestedScrollingChild {/*** Enable or disable nested scrolling for this view.** <p>If this property is set to true the view will be permitted to initiate nested* scrolling operations with a compatible parent view in the current hierarchy. If this* view does not implement nested scrolling this will have no effect. Disabling nested scrolling* while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping}* the nested scroll.</p>** @param enabled true to enable nested scrolling, false to disable** @see #isNestedScrollingEnabled()*/public void setNestedScrollingEnabled(boolean enabled);/*** Returns true if nested scrolling is enabled for this view.** <p>If nested scrolling is enabled and this View class implementation supports it,* this view will act as a nested scrolling child view when applicable, forwarding data* about the scroll operation in progress to a compatible and cooperating nested scrolling* parent.</p>** @return true if nested scrolling is enabled** @see #setNestedScrollingEnabled(boolean)*/public boolean isNestedScrollingEnabled();/*** Begin a nestable scroll operation along the given axes.** <p>A view starting a nested scroll promises to abide by the following contract:</p>** <p>The view will call startNestedScroll upon initiating a scroll operation. In the case* of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.* In the case of touch scrolling the nested scroll will be terminated automatically in* the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.* In the event of programmatic scrolling the caller must explicitly call* {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p>** <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.* If it returns false the caller may ignore the rest of this contract until the next scroll.* Calling startNestedScroll while a nested scroll is already in progress will return true.</p>** <p>At each incremental step of the scroll the caller should invoke* {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll}* once it has calculated the requested scrolling delta. If it returns true the nested scrolling* parent at least partially consumed the scroll and the caller should adjust the amount it* scrolls by.</p>** <p>After applying the remainder of the scroll delta the caller should invoke* {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing* both the delta consumed and the delta unconsumed. A nested scrolling parent may treat* these values differently. See* {@link NestedScrollingParent#onNestedScroll(View, int, int, int, int)}.* </p>** @param axes Flags consisting of a combination of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}*             and/or {@link ViewCompat#SCROLL_AXIS_VERTICAL}.* @return true if a cooperative parent was found and nested scrolling has been enabled for*         the current gesture.** @see #stopNestedScroll()* @see #dispatchNestedPreScroll(int, int, int[], int[])* @see #dispatchNestedScroll(int, int, int, int, int[])*/public boolean startNestedScroll(int axes);/*** Stop a nested scroll in progress.** <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>** @see #startNestedScroll(int)*/public void stopNestedScroll();/*** Returns true if this view has a nested scrolling parent.** <p>The presence of a nested scrolling parent indicates that this view has initiated* a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>** @return whether this view has a nested scrolling parent*/public boolean hasNestedScrollingParent();/*** Dispatch one step of a nested scroll in progress.** <p>Implementations of views that support nested scrolling should call this to report* info about a scroll in progress to the current nested scrolling parent. If a nested scroll* is not currently in progress or nested scrolling is not* {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p>** <p>Compatible View implementations should also call* {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before* consuming a component of the scroll event themselves.</p>** @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step* @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step* @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view* @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view* @param offsetInWindow Optional. If not null, on return this will contain the offset*                       in local view coordinates of this view from before this operation*                       to after it completes. View implementations may use this to adjust*                       expected input coordinate tracking.* @return true if the event was dispatched, false if it could not be dispatched.* @see #dispatchNestedPreScroll(int, int, int[], int[])*/public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);/*** Dispatch one step of a nested scroll in progress before this view consumes any portion of it.** <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.* <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested* scrolling operation to consume some or all of the scroll operation before the child view* consumes it.</p>** @param dx Horizontal scroll distance in pixels* @param dy Vertical scroll distance in pixels* @param consumed Output. If not null, consumed[0] will contain the consumed component of dx*                 and consumed[1] the consumed dy.* @param offsetInWindow Optional. If not null, on return this will contain the offset*                       in local view coordinates of this view from before this operation*                       to after it completes. View implementations may use this to adjust*                       expected input coordinate tracking.* @return true if the parent consumed some or all of the scroll delta* @see #dispatchNestedScroll(int, int, int, int, int[])*/public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);/*** Dispatch a fling to a nested scrolling parent.** <p>This method should be used to indicate that a nested scrolling child has detected* suitable conditions for a fling. Generally this means that a touch scroll has ended with a* {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds* the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}* along a scrollable axis.</p>** <p>If a nested scrolling child view would normally fling but it is at the edge of* its own content, it can use this method to delegate the fling to its nested scrolling* parent instead. The parent may optionally consume the fling or observe a child fling.</p>** @param velocityX Horizontal fling velocity in pixels per second* @param velocityY Vertical fling velocity in pixels per second* @param consumed true if the child consumed the fling, false otherwise* @return true if the nested scrolling parent consumed or otherwise reacted to the fling*/public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);/*** Dispatch a fling to a nested scrolling parent before it is processed by this view.** <p>Nested pre-fling events are to nested fling events what touch intercept is to touch* and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code>* offsets an opportunity for the parent view in a nested fling to fully consume the fling* before the child view consumes it. If this method returns <code>true</code>, a nested* parent view consumed the fling and this view should not scroll as a result.</p>** <p>For a better user experience, only one view in a nested scrolling chain should consume* the fling at a time. If a parent view consumed the fling this method will return false.* Custom view implementations should account for this in two ways:</p>** <ul>*     <li>If a custom view is paged and needs to settle to a fixed page-point, do not*     call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid*     position regardless.</li>*     <li>If a nested parent does consume the fling, this view should not scroll at all,*     even to settle back to a valid idle position.</li>* </ul>** <p>Views should also not offer fling velocities to nested parent views along an axis* where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView}* should not offer a horizontal fling velocity to its parents since scrolling along that* axis is not permitted and carrying velocity along that motion does not make sense.</p>** @param velocityX Horizontal fling velocity in pixels per second* @param velocityY Vertical fling velocity in pixels per second* @return true if a nested scrolling parent consumed the fling*/public boolean dispatchNestedPreFling(float velocityX, float velocityY);
}

有9个函数,简单说明一下:

1,setNestedScrollingEnabled 实现该接口的View要调用setNestedScrollingEnabled(true)才干够使用嵌套滚动.

2,isNestedScrollingEnabled推断当前view是否能使用嵌套滚动.

3,startNestedScroll和stopNestedScroll.是配对使用的.startNestedScroll表示view開始滚动了,通常是在ACTION_DOWN中调用。是来查找是否有嵌套处理的父View.在事件结束比方ACTION_UP或者ACTION_CANCLE中调用stopNestedScroll,告诉父布局滚动结束.

4dispatchNestedPreScroll,在该view消费滚动距离之前把总得滑动距离传给父布局.

5,dispatchNestedScroll,在该view消费滚动距离之后,把剩下的滑动距离再次传给父布局.

6,dispatchNestedFling和dispatchNestedPreFling就是把view传递滑动的信息给父布局的.比方滑动速度

NestedScrollingChildHelper这个类是一个辅助类就来把View的消息传递嵌套的父View。

所以上面函数内部实现基本上都是调用NestedScrollingChildHelper这类的函数,咱看一个:

NestedScrollingChildHelper的startNestedScroll()函数。一般就是在NestedScrollingChild的startNestedScroll()函数里调用。參数表示方向,有两个值ViewCompat.SCROLL_AXIS_HORIZONTAL ,ViewCompat.SCROLL_AXIS_VERTICAL

public boolean startNestedScroll(int axes) {if (hasNestedScrollingParent()) {// Already in progressreturn 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;}

上面就是寻找能够响应嵌套滑动的父View,也就是调用父类的onStartNestedScroll(),这个函数是NestedScrollingParent接口的函数。所以嵌套滑动的父View要实现这个接口,接着往下看,最后会有一个demo測试嵌套滑动

接着来看NestedScrollingParent这个接口:

/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.support.v4.view;import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;/*** This interface should be implemented by {@link android.view.ViewGroup ViewGroup} subclasses* that wish to support scrolling operations delegated by a nested child view.** <p>Classes implementing this interface should create a final instance of a* {@link NestedScrollingParentHelper} as a field and delegate any View or ViewGroup methods* to the <code>NestedScrollingParentHelper</code> methods of the same signature.</p>** <p>Views invoking nested scrolling functionality should always do so from the relevant* {@link ViewCompat}, {@link ViewGroupCompat} or {@link ViewParentCompat} compatibility* shim static methods. This ensures interoperability with nested scrolling views on Android* 5.0 Lollipop and newer.</p>*/
public interface NestedScrollingParent {/*** React to a descendant view initiating a nestable scroll operation, claiming the* nested scroll operation if appropriate.** <p>This method will be called in response to a descendant view invoking* {@link ViewCompat#startNestedScroll(View, int)}. Each parent up the view hierarchy will be* given an opportunity to respond and claim the nested scrolling operation by returning* <code>true</code>.</p>** <p>This method may be overridden by ViewParent implementations to indicate when the view* is willing to support a nested scrolling operation that is about to begin. If it returns* true, this ViewParent will become the target view's nested scrolling parent for the duration* of the scroll operation in progress. When the nested scroll is finished this ViewParent* will receive a call to {@link #onStopNestedScroll(View)}.* </p>** @param child Direct child of this ViewParent containing target* @param target View that initiated the nested scroll* @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},*                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both* @return true if this ViewParent accepts the nested scroll operation*/public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);/*** React to the successful claiming of a nested scroll operation.** <p>This method will be called after* {@link #onStartNestedScroll(View, View, int) onStartNestedScroll} returns true. It offers* an opportunity for the view and its superclasses to perform initial configuration* for the nested scroll. Implementations of this method should always call their superclass's* implementation of this method if one is present.</p>** @param child Direct child of this ViewParent containing target* @param target View that initiated the nested scroll* @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},*                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both* @see #onStartNestedScroll(View, View, int)* @see #onStopNestedScroll(View)*/public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);/*** React to a nested scroll operation ending.** <p>Perform cleanup after a nested scrolling operation.* This method will be called when a nested scroll stops, for example when a nested touch* scroll ends with a {@link MotionEvent#ACTION_UP} or {@link MotionEvent#ACTION_CANCEL} event.* Implementations of this method should always call their superclass's implementation of this* method if one is present.</p>** @param target View that initiated the nested scroll*/public void onStopNestedScroll(View target);/*** React to a nested scroll in progress.** <p>This method will be called when the ViewParent's current nested scrolling child view* dispatches a nested scroll event. To receive calls to this method the ViewParent must have* previously returned <code>true</code> for a call to* {@link #onStartNestedScroll(View, View, int)}.</p>** <p>Both the consumed and unconsumed portions of the scroll distance are reported to the* ViewParent. An implementation may choose to use the consumed portion to match or chase scroll* position of multiple child elements, for example. The unconsumed portion may be used to* allow continuous dragging of multiple scrolling or draggable elements, such as scrolling* a list within a vertical drawer where the drawer begins dragging once the edge of inner* scrolling content is reached.</p>** @param target The descendent view controlling the nested scroll* @param dxConsumed Horizontal scroll distance in pixels already consumed by target* @param dyConsumed Vertical scroll distance in pixels already consumed by target* @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target* @param dyUnconsumed Vertical scroll distance in pixels not consumed by target*/public void onNestedScroll(View target, int dxConsumed, int dyConsumed,int dxUnconsumed, int dyUnconsumed);/*** React to a nested scroll in progress before the target view consumes a portion of the scroll.** <p>When working with nested scrolling often the parent view may want an opportunity* to consume the scroll before the nested scrolling child does. An example of this is a* drawer that contains a scrollable list. The user will want to be able to scroll the list* fully into view before the list itself begins scrolling.</p>** <p><code>onNestedPreScroll</code> is called when a nested scrolling child invokes* {@link View#dispatchNestedPreScroll(int, int, int[], int[])}. The implementation should* report how any pixels of the scroll reported by dx, dy were consumed in the* <code>consumed</code> array. Index 0 corresponds to dx and index 1 corresponds to dy.* This parameter will never be null. Initial values for consumed[0] and consumed[1]* will always be 0.</p>** @param target View that initiated the nested scroll* @param dx Horizontal scroll distance in pixels* @param dy Vertical scroll distance in pixels* @param consumed Output. The horizontal and vertical scroll distance consumed by this parent*/public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);/*** Request a fling from a nested scroll.** <p>This method signifies that a nested scrolling child has detected suitable conditions* for a fling. Generally this means that a touch scroll has ended with a* {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds* the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}* along a scrollable axis.</p>** <p>If a nested scrolling child view would normally fling but it is at the edge of* its own content, it can use this method to delegate the fling to its nested scrolling* parent instead. The parent may optionally consume the fling or observe a child fling.</p>** @param target View that initiated the nested scroll* @param velocityX Horizontal velocity in pixels per second* @param velocityY Vertical velocity in pixels per second* @param consumed true if the child consumed the fling, false otherwise* @return true if this parent consumed or otherwise reacted to the fling*/public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);/*** React to a nested fling before the target view consumes it.** <p>This method siginfies that a nested scrolling child has detected a fling with the given* velocity along each axis. Generally this means that a touch scroll has ended with a* {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds* the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}* along a scrollable axis.</p>** <p>If a nested scrolling parent is consuming motion as part of a* {@link #onNestedPreScroll(View, int, int, int[]) pre-scroll}, it may be appropriate for* it to also consume the pre-fling to complete that same motion. By returning* <code>true</code> from this method, the parent indicates that the child should not* fling its own internal content as well.</p>** @param target View that initiated the nested scroll* @param velocityX Horizontal velocity in pixels per second* @param velocityY Vertical velocity in pixels per second* @return true if this parent consumed the fling ahead of the target view*/public boolean onNestedPreFling(View target, float velocityX, float velocityY);/*** Return the current axes of nested scrolling for this NestedScrollingParent.** <p>A NestedScrollingParent returning something other than {@link ViewCompat#SCROLL_AXIS_NONE}* is currently acting as a nested scrolling parent for one or more descendant views in* the hierarchy.</p>** @return Flags indicating the current axes of nested scrolling* @see ViewCompat#SCROLL_AXIS_HORIZONTAL* @see ViewCompat#SCROLL_AXIS_VERTICAL* @see ViewCompat#SCROLL_AXIS_NONE*/public int getNestedScrollAxes();
}

8个函数。简介一下:

1,onStartNestedScroll.当子view的调用NestedScrollingChild的方法startNestedScroll时,会调用该方法.前面分析到了

2,onNestedScrollAccepted.假设onStartNestedScroll方法返回的是true的话,那么紧接着就会调用该方法.它是让嵌套滚动在開始滚动之前,让布局容器(viewGroup)或者它的父类运行一些配置的初始化的.

3,onStopNestedScroll停止滚动了,当子view调用stopNestedScroll时会调用该方法.

4,onNestedScroll,当子view调用dispatchNestedScroll方法时,会调用该方法.

5,onNestedPreScroll,当子view调用dispatchNestedPreScroll方法是,会调用该方法.

6,dispatchNestedFling和dispatchNestedPreFling相应的就是滑动了.

相同NestedScrollingParent也有一个帮助类NestedScrollingParentHelper来实现嵌套滑动

由上能够知道这四个类(接口)两两相应,以下一个表格表示相应方法调用顺序,借了一张图过来

还有另外两个相应函数没贴上。

以下通过一个demo来測试一下。毕竟讲的再多不如实践一次

来张效果图:

demo实现就是滑动子View的时候假设滑动距离小于某个值。就仅仅平移父View(滑动距离所有给父View消耗),当大于这个值时。两者之差的值就让子View平移,这里仅仅是測试函数调用顺序,一些数据处理大家不要在意哈。
看代码:
子View:
package cj.com.nestedscrollingdemo;import android.content.Context;
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 {private static final String TAG = "Test";private NestedScrollingChildHelper mChildHelper;private int[] mConsumed = new int[2];private int[] mOffset = new int[2];public NestScrollingView(Context context) {super(context);init();}public NestScrollingView(Context context, AttributeSet attrs) {super(context, attrs);init();}public NestScrollingView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mChildHelper = new NestedScrollingChildHelper(this);setNestedScrollingEnabled(true);}@Overridepublic void setNestedScrollingEnabled(boolean enabled) {mChildHelper.setNestedScrollingEnabled(enabled);}@Overridepublic boolean isNestedScrollingEnabled() {return mChildHelper.isNestedScrollingEnabled();//return super.isNestedScrollingEnabled();}@Overridepublic boolean startNestedScroll(int axes) {//Log.d(TAG, "NestScrollingView  startNestedScroll");return mChildHelper.startNestedScroll(axes);//return super.startNestedScroll(axes);}@Overridepublic void stopNestedScroll() {Log.d(TAG, "NestScrollingView  stopNestedScroll");mChildHelper.stopNestedScroll();// super.stopNestedScroll();}@Overridepublic boolean hasNestedScrollingParent() {Log.d(TAG, "NestScrollingView  hasNestedScrollingParent");return mChildHelper.hasNestedScrollingParent();//return super.hasNestedScrollingParent();}@Overridepublic boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {Log.d(TAG, "NestScrollingView  dispatchNestedScroll");return mChildHelper.dispatchNestedScroll(dxConsumed,dyConsumed,dxUnconsumed,dyUnconsumed,offsetInWindow);//return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);}/**** @param dx X方向的偏移量 传给父View 先让父View处理* @param dy y方向的偏移量* @param consumed  一个数组,   表示 x 方向 或 y 方向的偏移量 是否有被父View消费 返回的数据是父View消耗了多少* @param offsetInWindow  父View消费滑动事件后 导致该View的偏移量  这个由NestedScrollingChildHelper内部处理* @return  父View 是否消耗了传入的偏移*/@Overridepublic boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {Log.d(TAG, "NestScrollingView  dispatchNestedPreScroll");return mChildHelper.dispatchNestedPreScroll(dx,dy,consumed,offsetInWindow);// return super.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);}@Overridepublic boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {Log.d(TAG, "NestScrollingView  dispatchNestedFling");return mChildHelper.dispatchNestedFling(velocityX,velocityY,consumed);}@Overridepublic boolean dispatchNestedPreFling(float velocityX, float velocityY) {Log.d(TAG, "NestScrollingView  dispatchNestedPreFling");return mChildHelper.dispatchNestedPreFling(velocityX,velocityY);}private int lastX;private int lastY;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.d(TAG, "onTouchEvent  ACTION_DOWN ");// 按下事件调用startNestedScrolllastX = (int) event.getX();lastY = (int) event.getY();Log.d(TAG, "onTouchEvent  lastX = "+lastX+"  lasty="+lastY);startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);break;case MotionEvent.ACTION_MOVE:Log.d(TAG, "onTouchEvent  ACTION_MOVE ");int x = (int) event.getX();int y = (int) event.getY();int deltaX = x - lastX;int deltaY = y - lastY;Log.d(TAG, "onTouchEvent  x = "+x+"  y="+y);Log.d(TAG, "onTouchEvent  deltaX = "+deltaX+"  deltaY="+deltaY);dispatchNestedPreScroll(deltaX,deltaY,mConsumed,mOffset);Log.d(TAG, "onTouchEvent  mConsumed[0] = "+mConsumed[0]+"  mConsumed[1] = "+mConsumed[1]);Log.d(TAG, "onTouchEvent  offsetX = " + mOffset[0] + ",offsetY = " + mOffset[1]);if(deltaY>mConsumed[1]){setTranslationY(deltaY-mConsumed[1]);}dispatchNestedScroll(0,deltaY,deltaX,0,mOffset);break;case MotionEvent.ACTION_UP:Log.d(TAG, "onTouchEvent  ACTION_UP ");stopNestedScroll();break;default:break;}return true;}
}

由于我是在API 24上开发的,所以仅仅要继承View能够,由于View已经实现NestedScrollingChild接口的所有函数,为了安全起见。不妨实现这个接口,事件的開始由子View開始,所以在onTouchEvent()函数里開始和父View一起处理事件。

父View:相同父View最好也实现NestedScrollingParent接口
package cj.com.nestedscrollingdemo;import android.content.Context;
import android.support.v4.view.NestedScrollingChild;
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;/****/public class NestScrollingViewGroup extends FrameLayout {private NestedScrollingParentHelper mParentHelper;private static final String TAG = "Test";public NestScrollingViewGroup(Context context, AttributeSet attrs) {super(context, attrs);init();}public NestScrollingViewGroup(Context context) {super(context);init();}public NestScrollingViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mParentHelper = new NestedScrollingParentHelper(this);}@Overridepublic boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {Log.d(TAG, "NestScrollingViewGroup  onStartNestedScroll  nestedScrollAxes ="+nestedScrollAxes);return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;}@Overridepublic void onNestedScrollAccepted(View child, View target, int axes) {Log.d(TAG, "NestScrollingViewGroup  onNestedScrollAccepted axes="+axes);mParentHelper.onNestedScrollAccepted(child, target, axes);}@Overridepublic void onStopNestedScroll(View child) {Log.d(TAG, "NestScrollingViewGroup  onStopNestedScroll");mParentHelper.onStopNestedScroll(child);}@Overridepublic void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {Log.d(TAG, "NestScrollingViewGroup  onNestedScroll");Log.d(TAG, "    dxConsumed="+dxConsumed+"   dyConsumed="+dyConsumed+"   dxUnconsumed="+dxUnconsumed+"   dyUnconsumed="+dyUnconsumed);}@Overridepublic void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {Log.d(TAG, "NestScrollingViewGroup  onNestedPreScroll");Log.d(TAG, "    dx="+dx+"   dy="+dy+"   consumed[0]="+consumed[0]+"   consumed[1]="+consumed[1]);if(dy<=80){setTranslationY(dy);consumed[0] = 0;consumed[1] = dy;}else{//...setTranslationY(80);consumed[0] = 0;consumed[1] = 80;}}@Overridepublic boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {Log.d(TAG, "NestScrollingViewGroup  onNestedFling");return super.onNestedFling(target, velocityX, velocityY, consumed);}@Overridepublic boolean onNestedPreFling(View target, float velocityX, float velocityY) {Log.d(TAG, "NestScrollingViewGroup  onNestedPreFling");return super.onNestedPreFling(target, velocityX, velocityY);}@Overridepublic int getNestedScrollAxes() {Log.d(TAG, "NestScrollingViewGroup  getNestedScrollAxes");return mParentHelper.getNestedScrollAxes();}
}

布局文件:

<?

xml version="1.0" encoding="utf-8"?

> <cj.com.nestedscrollingdemo.NestScrollingViewGroup xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:background="#f00" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="cj.com.nestedscrollingdemo.MainActivity"> <cj.com.nestedscrollingdemo.NestScrollingView android:background="#0f0" android:layout_width="300dp" android:layout_height="300dp" /> </cj.com.nestedscrollingdemo.NestScrollingViewGroup>

看一下log:
D/Test: NestScrollingView  stopNestedScroll
D/Test: onTouchEvent  ACTION_DOWN
D/Test: onTouchEvent  lastX = 261  lasty=269
D/Test: NestScrollingView  startNestedScroll
D/Test: NestScrollingViewGroup  onStartNestedScroll  nestedScrollAxes =2
D/Test: NestScrollingViewGroup  onNestedScrollAccepted axes=2
D/Test: onTouchEvent  ACTION_MOVE
D/Test: onTouchEvent  x = 264  y=276
D/Test: onTouchEvent  deltaX = 3  deltaY=7
D/Test: NestScrollingView  dispatchNestedPreScroll
D/Test: NestScrollingViewGroup  onNestedPreScroll
D/Test:     dx=3   dy=7   consumed[0]=0   consumed[1]=0
D/Test: onTouchEvent  mConsumed[0] = 0  mConsumed[1] = 7
D/Test: onTouchEvent  offsetX = 0,offsetY = 7
D/Test: NestScrollingView  dispatchNestedScroll
D/Test: NestScrollingViewGroup  onNestedScroll
D/Test:     dxConsumed=0   dyConsumed=7   dxUnconsumed=3   dyUnconsumed=0
D/Test: onTouchEvent  ACTION_MOVE
D/Test: onTouchEvent  x = 261  y=282
D/Test: onTouchEvent  deltaX = 0  deltaY=13
D/Test: NestScrollingView  dispatchNestedPreScroll
D/Test: NestScrollingViewGroup  onNestedPreScroll
D/Test:     dx=0   dy=13   consumed[0]=0   consumed[1]=0
D/Test: onTouchEvent  mConsumed[0] = 0  mConsumed[1] = 13
D/Test: onTouchEvent  offsetX = 0,offsetY = 6
D/Test: NestScrollingView  dispatchNestedScroll
D/Test: NestScrollingViewGroup  onNestedScroll
D/Test:     dxConsumed=0   dyConsumed=13   dxUnconsumed=0   dyUnconsumed=0
D/Test: onTouchEvent  ACTION_MOVE
D/Test: onTouchEvent  x = 258  y=283
D/Test: onTouchEvent  deltaX = -3  deltaY=14
D/Test: NestScrollingView  dispatchNestedPreScroll
D/Test: NestScrollingViewGroup  onNe

log没贴全然,有点多,通过这一部分就能够知道流程了

通过一个小demo,能够加深我们对嵌套滑动机制的理解。

android滑动嵌套应用还是蛮多的。

比方CoordinatorLayout及子view使用Behavior来实现嵌套滑动。Behavior内部都有NestedScrollingChild。NestedScrollingParent的类似的函数。

转载于:https://www.cnblogs.com/zhchoutai/p/8577959.html

使用Android SwipeRefreshLayout了解Android的嵌套滑动机制相关推荐

  1. RecycleView嵌套滑动机制

    Android 5.0推出了嵌套滑动机制,在之前,一旦子View处理了触摸事件,父View就没有机会再处理这次的触摸事件,而嵌套滑动机制解决了这个问题,能够实现如下效果: 为了支持嵌套滑动,子View ...

  2. android 嵌套分组拖动_Android NestedScrolling嵌套滑动机制

    Android NestedScrolling嵌套滑动机制 最近项目要用到官网的下拉刷新SwipeRefreshLayout,它是个容器,包裹各种控件实现下拉,不像以前自己要实现事件的拦截,都是通过对 ...

  3. 干货:五分钟带你看懂NestedScrolling嵌套滑动机制

    Android NestedScrolling嵌套滑动机制 Android在发布5.0之后加入了嵌套滑动机制NestedScrolling,为嵌套滑动提供了更方便的处理方案.在此对嵌套滑动机制进行详细 ...

  4. android控件的touch事件_聊聊Android嵌套滑动

    聊聊Android嵌套滑动 最近工作中遇到了需求是使用 Bottom-Sheet 交互的弹窗,使用了 design 包里面的 CoordinatorLayout 和 BottomSheetBehavi ...

  5. 向下滑动动画android_Android SwipeRefreshLayout – Android向下拉动/向下滑动即可刷新

    向下滑动动画android In this tutorial we'll discuss and implement Android Swipe Down to Refresh or Android ...

  6. Android 实现嵌套滑动

    前言 Android实现简易版滑动 上次文章中实现了简易的ScrollerView滑动,但实际使用中许多场景都会涉及到嵌套滑动,在今天的博文中我们基于上次的ScrollLayout来进一步实现嵌套滑动 ...

  7. layui totalRow 多层嵌套json_自定义 Behavior,实现嵌套滑动、平滑切换周月视图的日历...

    使用 CoordinateLayout 可以协调它的子布局,实现滑动效果的联动,它的滑动效果由 Behavior 实现.以前用过小米日历,对它滑动平滑切换日月视图的效果印象深刻.本文尝试用自定义 Be ...

  8. android SwipeRefreshLayout嵌套Webview滑动冲突问题解决

    最近有一个需求,需要在网页中实现下拉刷新功能,这里遇到一个坑,加载网页的时候webview向上滑动不了了,看了一下网上的资料尝试过后都没有用,所以在这里做一下记录,希望可以帮到大家,由于两个控件都有滑 ...

  9. Android嵌套滑动冲突

    android在嵌套滑动的时候会产生滑动冲突.之前我也碰到,但是以前的笔记本丢失了,所以只能重新再写一章. 一.会产生滑动冲突的情况 那么什么时候会产生滑动冲突呢?比如你有个activity,acti ...

最新文章

  1. John的农场(最小生成树)
  2. 数据量很大,分页查询很慢,怎么破?
  3. 窗口缩小 怎么让定位的盒子不动_盒子模型
  4. 前端学习(2473):创建页面组件
  5. 保证你现在和未来不失业的十种关键技术
  6. linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用
  7. Linux显卡驱动|CUDA卸载和安装|pytorch安装
  8. C++ vector库学习笔记
  9. javascript-从toString方法在判断复杂数据类型上的妙用,引申到对原型链的理解...
  10. java 对象流 乱码,JAVA 中的 IO 流
  11. 1.多线程和单线程简单比较
  12. 用matlab做bp神经网络预测,matlab人工神经网络预测
  13. 高等数学(第七版)同济大学 习题7-5 个人解答
  14. MATLAB函数拟合使用
  15. pm模式 raid_Adaptec RAID PM8060 用户手册.pdf
  16. android显示emoji,android兼容emoji显示以及检测是否支持emoji
  17. 变量的作用域与生命周期
  18. cesium 漫游飞行_Cesium 之三维漫游飞行效果实现篇
  19. sublime去掉空行 sublime批量删除空白行
  20. 未转变者入侵服务器后台,未转变者(unturned)联机服务器创建方法

热门文章

  1. 树莓派入门(一) - 下载安装系统镜像,Raspbian和Centos
  2. htonl(), ntohl(), htons(), ntohs() 函数具体应用
  3. 设置elment ui plus 的el table的边框线
  4. 浅谈黑盒测试和白盒测试
  5. C语言 - 隐式类型转换
  6. Voice conversion相关语音数据集综合汇总
  7. 听说高盛集体抗议 996 ,我们已经连 955 都不要了
  8. typora全局替换文本
  9. 如何制作GIF表情包,动态GIF怎么做
  10. 吉利车机安装第三方软件教程,手机修改dns完整操作教程