/**
* 该接口应该由{@link android.view.ViewGroup ViewGroup}子类实现
* 希望支持嵌套子视图委托的滚动操作。
*/
public interface NestedScrollingParent {
/**
* 有嵌套滑动,询问该父View是否接受嵌套滑动
*
* @param child 直接子类(层级 child >= target)
* @param target 发起嵌套滚动的视图
* @param axes 滚动方向 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
* {@link ViewCompat#SCROLL_AXIS_VERTICAL}
* @return 是否接受嵌套滑动
*/
boolean onStartNestedScroll(@NonNull View child, @NonNull View target, @ScrollAxis int axes);
/**
* 响应嵌套滚动的成功声明(接受嵌套滑动)
* onStartNestedScroll返回true,该函数被调用
*/
void onNestedScrollAccepted(@NonNull View child, @NonNull View target, @ScrollAxis int axes);
/**
* 停止嵌套滑动
*
* @param target 具体嵌套滑动的那个子类
*/
void onStopNestedScroll(@NonNull View target);
/**
* 响应进行中的嵌套滚动(嵌套滑动的子View在滑动之后传递过来的滑动情况)
*
* @param target 嵌套滑动的子View
* @param dxConsumed 水平方向target滑动的距离
* @param dyConsumed 竖直方向target滑动的距离
* @param dxUnconsumed 水平方向target未滑动的距离
* @param dyUnconsumed 竖直方向target未滑动的距离
*/
void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed);
/**
* 在嵌套滑动的子View未滑动之前,通知准备(响应target)滑动的情况
*
* @param target 嵌套滑动的View
* @param dx 水平方向target想要移动的距离
* @param dy 竖直方向target想要移动的距离
* @param consumed 输出结果,告诉子View当前父View消耗的距离,让子View做出相应调整
* consumed[0] 水平消耗的距离
* consumed[1] 垂直消耗的距离。
*/
void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed);
/**
* 嵌套滑动的子View在fling之后报告过来的fling情况
*
* @param target
* @param velocityX 水平方向速度
* @param velocityY 垂直方向速度
* @param consumed
* @return 父View是否消耗了fling
*/
boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed);
/**
* 在嵌套滑动的子View未fling之前告诉过来的准备fling的情况
*
* @param target 嵌套滑动的View
* @param velocityX 水平方向速度
* @param velocityY 垂直方向速度
* @return 父View是否消耗fling
*/
boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY);
/**
* 获得滚动方向
*
* @return 返回滚动轴
* @see ViewCompat#SCROLL_AXIS_HORIZONTAL
* @see ViewCompat#SCROLL_AXIS_VERTICAL
* @see ViewCompat#SCROLL_AXIS_NONE
*/
int getNestedScrollAxes();
}
/**
* 该接口应该由{@link android.view.View View}子类实现,这些子类希望
* 支持将嵌套滚动操作分配给协作父节点
*/
public interface NestedScrollingChild {
/**
* 设置是否启用嵌套滑动
*
* @param enabled 是否启用嵌套滚动
*/
void setNestedScrollingEnabled(boolean enabled);
/**
* 是否允许嵌套滑动
*
* @return 是否允许嵌套滑动
*/
boolean isNestedScrollingEnabled();
/**
* 通知开始嵌套滑动流程,调用该函数的时候会去找嵌套滑动的父控件
* 如果找到了父控件并且父控件说可以滑动就返回true,否则返回false
* (一般在ACTION_DOWN 事件类型中调用)
*
* @param axes 支持嵌套滑动轴:水平方向、垂直方向、或者不指定方向
* @return 父控件是否同意嵌套滑动。(onStartNestedScroll返回值)
*/
boolean startNestedScroll(@ScrollAxis int axes);
/**
* 停止嵌套滑动(一般在 ACTION_UP 中调用)
*/
void stopNestedScroll();
/**
* 如果该视图具有嵌套滚动父视图,则返回true。
*/
boolean hasNestedScrollingParent();
/**
* 分发嵌套滑动
*/
boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow);
/**
* 在嵌套滑动的子View滑动之前,告诉父View滑动额距离,让父View做相应的处理
*
* @param dx 告诉父View水平方向需要滑动的距离
* @param dy 告诉父View垂直方向需要滑动的距离
* @param consumed 如果不为NULL,则告诉子View父View的滑动情况:
* consumed[0] 父View告诉子View水平方向滑动的距离(dx)
* consumed[1] 父View告诉子View垂直方向滑动的距离(dy)
* @param offsetInWindow 可选,length=2的数组,如果父View滑动导致子View的窗口发生了变化(子View的位置发生变化)
* 该参数返回x(offsetInWindow[0]),y(offsetInWindow[1])方向的变化
* 如果你记录了手指最后的位置,需要根据参数offsetInWindow计算偏移量,
* 才能保证下一次的touch事件的计算是正确的。
* @return true 父View滑动了;false 父View没有滑动。
*/
boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
@Nullable int[] offsetInWindow);
/**
* 在嵌套滑动的子View fling之后在调用该函数向父View汇报fling情况
*
* @param velocityX 水平方向速度
* @param velocityY 垂直方向速度
* @param consumed true:子View fling了,false:子View没有 fling
* @return true 父View fling了
*/
boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);
/**
* 在嵌套滑动的子View fling之前告诉父View fling情况
*
* @param velocityX 水平方向的速度
* @param velocityY 垂直方向的速度
* @return true: 父View fling了
*/
boolean dispatchNestedPreFling(float velocityX, float velocityY);
}
NestedScrollingParent
和 NestedScrollingChild
方法看似很多,但是总结起来可以看到
Child中的方法和Parent方法是存在对应关系的,在Child接口中对Scroll和Fling事件进行分发,在Parent接口中对Scroll和Fling事件进行响应。
dispatchNestedPreScroll()
、dispatchNestedScroll()
onNestedPreScroll()
、onNestedScroll()
dispatchNestedPreFling()
、dispatchNestedFling()
onNestedPreFling()
、onNestedFling()
NestedScrollingChildHelper 和 NestedScrollingParentHelper 是帮助我们实现嵌套滑动的辅助类。
NestedScrollingChild 和 NestedScrollingChildHelper 中的方法是一一对应的,如果需要通知Parent实现嵌套滑动,需要借助 NestedScrollingChildHelper 中的方法。
同理 NestedScrollingParent 和 NestedScrollingParentHelper 中的方法也是一一对应的,也需要调用NestedScrollingParentHelper 中的方法,通知Child。
下面通过两个具体的例子加深理解。
效果图:
代码实现:
public class NestedScrollingView extends ViewGroup implements NestedScrollingParent {
/**
* ZoomView
*/
private View mZoomView;
/**
* recyclerView
*/
private View mRecyclerView;
/**
* ZoomView高度
*/
private int mZoomHeight;
/**
* ZoomView最大高度
*/
private int mMaxHeight;
/**
* ContentView回弹Top
*/
private int mNormalTop;
/**
* ZoomView宽高比
*/
private float mRatio = 1.8f;
/**
* RecyclerView 距离顶部位置
*/
private int mTop;
private boolean isLayout;
private ValueAnimator mValueAnimator;
private int mLastValue;
private NestedScrollingParentHelper mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
public NestedScrollingView(Context context) {
this(context, null);
}
public NestedScrollingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setZoomHeight(int zoomHeight) {
mZoomHeight = zoomHeight;
mNormalTop = mZoomHeight / 2;
mMaxHeight = (int) (mZoomHeight * mRatio);
mTop = mNormalTop;
}
public void setView(View zoomView, View recyclerView) {
this.mZoomView = zoomView;
this.mRecyclerView = recyclerView;
requestLayout();
}
public void setMarginTop(int marginTop) {
this.mNormalTop = marginTop;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mZoomView != null) {
measureChild(mZoomView, widthMeasureSpec, heightMeasureSpec);
}
if (mRecyclerView != null) {
measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mZoomView != null && mRecyclerView != null) {
if (!isLayout) {
isLayout = true;
mRecyclerView.layout(0, mTop,
mRecyclerView.getMeasuredWidth(), mTop + mRecyclerView.getMeasuredHeight());
}
mZoomView.layout(mZoomView.getLeft(), 0,
mZoomView.getLeft() + mZoomView.getMeasuredWidth(),
mZoomView.getTop() + mZoomView.getMeasuredHeight());
}
}
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return mZoomView != null && mRecyclerView != null;
}
@Override
public void onNestedScrollAccepted(View child, View target, int axes) {
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
cancelAnim();
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(target, dx, dy, consumed);
mTop = mRecyclerView.getTop();
// 向上滑动
if (dy > 0 && mTop > 0) {
// 告诉RecyclerView,父布局消耗的距离。否则RecyclerView的item会跟随滚动
consumed[1] = dy;
mRecyclerView.offsetTopAndBottom(-dy);
} else if (dy < 0) {
// recyclerView是否滚动到顶部,不能继续下拉
boolean scrollTop = !mRecyclerView.canScrollVertically(-1);
if (scrollTop && mTop < mMaxHeight) {
mRecyclerView.offsetTopAndBottom(-dy);
consumed[1] = dy;
}
}
// 纠正偏移
if (mTop < 0) {
mRecyclerView.offsetTopAndBottom(-mTop);
} else if (mTop > mMaxHeight) {
mRecyclerView.offsetTopAndBottom(mMaxHeight - mTop);
}
if (mTop > mNormalTop) {
zoomAnim();
}
}
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
if (mTop == 0){
return super.onNestedPreFling(target, velocityX, velocityY);
}else{
// recyclerView没有滑倒顶部,禁用Fling
return true;
}
}
@Override
public void onStopNestedScroll(View child) {
if (mTop > mNormalTop) {
resetAnim();
}
mNestedScrollingParentHelper.onStopNestedScroll(child);
}
/**
* ZoomView动画
*/
private void zoomAnim(){
int zoomDy = (int) ((mTop - mNormalTop) * getUnit());
ViewGroup.LayoutParams lp = mZoomView.getLayoutParams();
lp.height = mZoomHeight + zoomDy;
mZoomView.setLayoutParams(lp);
}
/**
* 复位动画
*/
private void resetAnim() {
mLastValue = mTop;
mValueAnimator = ValueAnimator.ofInt(mTop, mNormalTop);
mValueAnimator.setDuration(250L);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
int offset = value - mLastValue;
mRecyclerView.offsetTopAndBottom(offset);
mLastValue = value;
mTop = mRecyclerView.getTop();
zoomAnim();
}
});
mValueAnimator.start();
}
/**
* 清除动画
*/
private void cancelAnim() {
if (mValueAnimator != null && mValueAnimator.isRunning()) {
mValueAnimator.cancel();
}
}
/**
* 图片伸缩量 / recyclerView位移量
*
* @return recyclerView移动一个像素,图片需要拉伸的像素
*/
private double getUnit(){
return 1.0 * (mMaxHeight - mZoomHeight) / (mMaxHeight - mNormalTop);
}
}
布局文件:
<com.example.test.nestedscroll.NestedScrollingView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#009688"
android:id="@+id/nested_scrolling"
>
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@mipmap/img4" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
com.example.test.nestedscroll.NestedScrollingView>
Activity代码:
mScrollingView.setZoomHeight(ScreenUtil.dp2px(200));
mScrollingView.setView(mImageView, mRecyclerView);
RecyclerView
已经实现了NestedScrollingChild
所以我们只需要对ParentView操作就行了。
这里面不能很好的体现NestedScrollingChildHelper 和 NestedScrollingParentHelper作用,下面一个例子可以很好的体现它们的作用。
当ChildView
滑动到 ParentView
的边缘的时候,继续拖动ChildView
,父View需要响应滑动事件。
NestedChildView实现如下:
public class NestedChildView extends View implements NestedScrollingChild {
private static final String TAG = "NestedChildView";
private float mDownX; // 手指第一次落下的x位置
private float mDownY; // 手指第一次落下的y位置
/**
* 接受父View消耗的值
*/
private int[] consumed = new int[2]; // 消耗的距离
private int[] offsetInWindow = new int[2]; // 窗口偏移
private NestedScrollingChildHelper mChildHelper;
public NestedChildView(Context context) {
this(context,null);
}
public NestedChildView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public NestedChildView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mChildHelper = new NestedScrollingChildHelper(this);
// 开启嵌套滑动
setNestedScrollingEnabled(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownX = x;
mDownY = y;
//开始滑动时,通知父View
startNestedScroll(ViewCompat.SCROLL_AXIS_HORIZONTAL
| ViewCompat.SCROLL_AXIS_VERTICAL);
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) (x - mDownX);
int dy = (int) (y - mDownY);
//分发触屏事件给父类处理
if (dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)){
//减掉父类消耗的距离
dx -= consumed[0];
dy -= consumed[1];
}
// 对Left和Right进行偏移
offsetLeftAndRight(dx);
// 对Top和Bottom进行偏移
offsetTopAndBottom(dy);
break;
case MotionEvent.ACTION_UP:
stopNestedScroll();
break;
}
return true;
}
/**
* 设置是否允许嵌套滑动
*
* @param enabled
*/
@Override
public void setNestedScrollingEnabled(boolean enabled) {
Log.i(TAG,"设置是否允许嵌套欢动:" + enabled);
mChildHelper.setNestedScrollingEnabled(enabled);
}
/**
* 是否允许嵌套滑动
*
* @return
*/
@Override
public boolean isNestedScrollingEnabled() {
Log.i(TAG,"获得是否允许嵌套欢动:" + mChildHelper.isNestedScrollingEnabled());
return mChildHelper.isNestedScrollingEnabled();
}
/**
* 通知开始嵌套滑动流程,调用该函数的时候会去找嵌套滑动的父控件
* 如果找到了父控件并且父控件说可以滑动就返回true,否则返回false
* (一般在ACTION_DOWN 事件类型中调用)
*
* @param axes 支持嵌套滑动轴:水平方向、垂直方向、或者不指定方向
* @return
*/
@Override
public boolean startNestedScroll(int axes) {
Log.i(TAG,"startNestedScroll 开始滚动,通知父View");
return mChildHelper.startNestedScroll(axes);
}
/**
* 停止嵌套滑动(一般在 ACTION_UP 中调用)
*/
@Override
public void stopNestedScroll() {
Log.i(TAG,"stopNestedScroll 停止嵌套滚动");
mChildHelper.stopNestedScroll();
}
/**
* 是否有嵌套滑动对应的父控件
*
* @return
*/
@Override
public boolean hasNestedScrollingParent() {
Log.i(TAG,"是否有嵌套滚动的父View:" + mChildHelper.hasNestedScrollingParent());
return mChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
Log.i(TAG,"分发嵌套滑动 dispatchNestedScroll dxC:" + dxConsumed + " dyC:" + dyConsumed + " dxU:" + dxUnconsumed + " dyU:" + dyUnconsumed + " oI:" + offsetInWindow);
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
/**
* 在嵌套滑动的子View滑动之前,告诉父View滑动额距离,让父View做相应的处理
*
* @param dx 告诉父View水平方向需要滑动的距离
* @param dy 告诉父View垂直方向需要滑动的距离
* @param consumed 如果不为NULL,则告诉子View父View的滑动情况:
* consumed[0] 父View告诉子View水平方向滑动的距离(dx)
* consumed[1] 父View告诉子View垂直方向滑动的距离(dy)
* @param offsetInWindow 可选,length=2的数组,如果父View滑动导致子View的窗口发生了变化(子View的位置发生变化)
* 该参数返回x(offsetInWindow[0]),y(offsetInWindow[1])方向的变化
* 如果你记录了手指最后的位置,需要根据参数offsetInWindow计算偏移量,
* 才能保证下一次的touch事件的计算是正确的。
* @return true 父View滑动了;false 父View没有滑动。
*/
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
Log.i(TAG,"准备分发 dispatchNestedPreScroll dx:" + dx + " dy:" + dy + " cons:" + Arrays.toString(consumed) + " offs:" + Arrays.toString(offsetInWindow));
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
/**
* 在嵌套滑动的子View fling之后在调用该函数向父View汇报fling情况
*
* @param velocityX 水平方向速度
* @param velocityY 垂直方向速度
* @param consumed true:子View fling了,false:子View没有 fling
* @return true 父View fling了
*/
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
Log.i(TAG,"分发Fling dispatchNestedFling vX:" + velocityX + " vY:" + velocityY + " consumed:" + consumed);
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
/**
* 在嵌套滑动的子View fling之前告诉父View fling情况
*
* @param velocityX 水平方向的速度
* @param velocityY 垂直方向的速度
* @return true: 父View fling了
*/
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
Log.i(TAG,"准备分发Fling dispatchNestedPreFling vX:" + velocityX + " vY:" + velocityY);
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mChildHelper.onDetachedFromWindow();
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
Log.e(TAG,"onScrollChanged");
}
}
ChildView主要做了:
setNestedScrollingEnabled(true);
,内部调用mChildHelper.setNestedScrollingEnabled(enabled);
startNestedScroll()
通知父View开始嵌套滑动,内部调用mChildHelper.startNestedScroll(axes)
dispatchNestedPreScroll()
方法将滚动事件分发给父View,并接收父View消耗的距离,内部调用mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
NestedParentView
public class NestedParentView extends FrameLayout implements NestedScrollingParent {
private static final String TAG = "zzy 父View";
private NestedScrollingParentHelper mParentHelper;
public NestedParentView(@NonNull Context context) {
this(context,null);
}
public NestedParentView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public NestedParentView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mParentHelper = new NestedScrollingParentHelper(this);
}
/**
* 有嵌套滑动,询问该父View是否接受嵌套滑动
*
* @param child 直接子类(层级 child >= target)
* @param target 发起嵌套滚动的视图
* @param nestedScrollAxes
* @return 是否接受嵌套滑动
*/
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
Log.d(TAG,"onStartNestedScroll 收到子View嵌套滑动,返回true,跟随滑动。 " +
" child:" + child.getClass().getSimpleName() + " target:" + target.getClass().getSimpleName() + " axes: " + nestedScrollAxes);
return true;
}
/**
* 响应嵌套滚动的成功声明(接受嵌套滑动)
* onStartNestedScroll返回true,该函数被调用
*/
@Override
public void onNestedScrollAccepted(View child, View target, int axes) {
mParentHelper.onNestedScrollAccepted(child, target, axes);
Log.d(TAG,"onNestedScrollAccepted 已经接受嵌套滑动");
}
/**
* 停止嵌套滑动
*
* @param child 具体嵌套滑动的那个子类
*/
@Override
public void onStopNestedScroll(View child) {
Log.d(TAG,"onStopNestedScroll");
mParentHelper.onStopNestedScroll(child);
}
/**
* 响应进行中的嵌套滚动(嵌套滑动的子View在滑动之后传递过来的滑动情况)
*
* @param target 嵌套滑动的子View
* @param dxConsumed 水平方向target滑动的距离
* @param dyConsumed 竖直方向target滑动的距离
* @param dxUnconsumed 水平方向target未滑动的距离
* @param dyUnconsumed 竖直方向target未滑动的距离
*/
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
Log.d(TAG,"onNestedScroll");
}
/**
* 在嵌套滑动的子View未滑动之前,通知准备(响应target)滑动的情况
*
* @param target 嵌套滑动的View
* @param dx 水平方向target想要移动的距离
* @param dy 竖直方向target想要移动的距离
* @param consumed 输出结果,告诉子View当前父View消耗的距离,让子View做出相应调整
* consumed[0] 水平消耗的距离
* consumed[1] 垂直消耗的距离。
*/
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
final View child = target;
Log.d(TAG,"onNestedPreScroll 收到: dx:" + dx + " dy:" + dy + " consumed: " + Arrays.toString(consumed));
if (dx > 0){
if (child.getRight() + dx > getWidth()){
dx = child.getRight() + dx - getWidth(); //多出来的部分
offsetLeftAndRight(dx);
consumed[0] += dx; //父View消耗
}
}else {
if (child.getLeft() + dx < 0){
dx += child.getLeft();
offsetLeftAndRight(dx);
consumed[0] += dx; //父View消耗
}
}
if (dy > 0){
if (child.getBottom() + dy > getHeight()){
dy = child.getBottom() + dy - getHeight();
offsetTopAndBottom(dy);
consumed[1] += dy;
}
}else {
if (child.getTop() + dy < 0){
dy = dy + child.getTop();
offsetTopAndBottom(dy);
consumed[1] += dy;
}
}
Log.d(TAG,"onNestedPreScroll 输出: dx:" + dx + " dy:" + dy + " consumed: " + Arrays.toString(consumed));
}
/**
* 嵌套滑动的子View在fling之后报告过来的fling情况
*
* @param target
* @param velocityX
* @param velocityY
* @param consumed
* @return 父View是否消耗了fling
*/
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Log.d(TAG,"onNestedFling");
return false;
}
/**
*
* 在嵌套滑动的子View未fling之前告诉过来的准备fling的情况
* @param target 嵌套滑动的View
* @param velocityX
* @param velocityY
* @return 父View是否消耗fling
*/
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
Log.d(TAG,"onNestedPreFling");
return false;
}
/**
* 获得滚动方向
*
* @return 返回滚动轴
* @see ViewCompat#SCROLL_AXIS_HORIZONTAL
* @see ViewCompat#SCROLL_AXIS_VERTICAL
* @see ViewCompat#SCROLL_AXIS_NONE
*/
@Override
public int getNestedScrollAxes() {
return super.getNestedScrollAxes();
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
Log.e(TAG,"onScrollChanged");
}
}
我练习的时候就是用的这个例子,出处已经找不到了。