承接上文 NestedScrollingParent 实现复杂交互效果 ,在 NestedScroll
这一套流程中,NestedScrollingChild
不用考虑怎么去通知父布局如何滚动,只需要负责自己的事情:产生滚动事件,并将事件共享出去,产生 fling 事件,共享 fling 。
NestedScrollingParent 简称 NP
NestedScrollingChild 简称 NC
NC 调用 startNestedScroll()
通知 NP 的 onStartNestedScroll
(具体是怎么通知到 NP 的参考 源码)
NC 产生一个 Touch 事件,如滚动 5 个像素,然后调用 dispatchNestedPreScroll
通知 NP 自己要滚动 5个像素, NP 收到通知后根据自身需要进行消费,如消费了 2 个像素,然后将结果通知到 NC
NC 将剩下的 3 个像素进行自身消费,如此时滚动了 2 个像素到达了边界,还剩下 1 个像素没有消费掉,然后就调用 dispatchNestedScroll
将剩下的未消费的 1 个像素共享出去。
Fling 事件类似 Scroll 事件
/**
* Created by hanks on 16/8/30.
*/
public class CodeWebView extends WebView implements NestedScrollingChild, ScrollListener {
public static final String TAG = CodeWebView.class.getSimpleName();
public static final int UP = 1;
public static final int DOWN = -1;
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private final int mTouchSlop;
private final int mMinimumVelocity;
private final int mMaximumVelocity;
private int direction = DOWN; // TODO 还需要同步到父布局的方向
private int mLastMotionY;
private int mNestedYOffset;
private NestedScrollingChildHelper mChildHelper;
private VelocityTracker mVelocityTracker;
private boolean allowFly;
private int downY;
private float mDownY = -1;
public CodeWebView(Context context) {
this(context, null);
}
public CodeWebView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CodeWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mChildHelper = new NestedScrollingChildHelper(this); // 辅助类
setNestedScrollingEnabled(true); // 设置支持 NestedScrolling
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean eventAddedToVelocityTracker = false;
final int action = MotionEventCompat.getActionMasked(event);
final int actionIndex = MotionEventCompat.getActionIndex(event);
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
switch (action) {
case MotionEvent.ACTION_DOWN:
allowFly = false;
downY = (int) event.getRawY();
// 开始 NestedScroll
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) event.getRawY();
int dy = -(moveY - downY); //滚动方法的方向跟坐标是相反的,所以这里要加一个负号
downY = moveY;
//在consumed 中就是父类滑动的距离,
if (dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)) {
dy -= mScrollConsumed[1]; // 减去父类消费的距离
scrollBy(0, dy); // 剩下的自己消费
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mVelocityTracker.addMovement(event);
eventAddedToVelocityTracker = true;
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int mScrollPointerId = MotionEventCompat.getPointerId(event, actionIndex);
float vY = -VelocityTrackerCompat.getYVelocity(mVelocityTracker, mScrollPointerId);
// 产生 fling 事件
if (Math.abs(vY) > mMinimumVelocity && !dispatchNestedPreFling(0, vY)) {
dispatchNestedFling(0, vY, true);
logi("dispatchNestedFling");
}
resetTouch();
break;
}
if (!eventAddedToVelocityTracker) {
mVelocityTracker.addMovement(event);
}
return true;
}
private void resetTouch() {
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
stopNestedScroll();
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
@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);
}
public void log(String s) {
Log.e(TAG, s);
}
public void logi(String s) {
Log.i(TAG, s);
}
public void logw(String s) {
Log.w(TAG, s);
}
}
文章来自: http://hanks.xyz