package com.wangdaye.mysplash.common.ui.widget.nestedScrollView; import android.content.Context; import android.os.Build; import android.support.annotation.IntDef; import android.support.annotation.RequiresApi; import android.support.v4.view.NestedScrollingChild; import android.support.v4.view.NestedScrollingChildHelper; import android.support.v4.view.NestedScrollingParent; import android.support.v4.view.NestedScrollingParentHelper; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.FrameLayout; /** * Nested scroll frame layout. * * This FrameLayout can dispatch nested scrolling action. * * */ public abstract class NestedScrollFrameLayout extends FrameLayout implements NestedScrollingChild, NestedScrollingParent { private NestedScrollingChildHelper nestedScrollingChildHelper; private NestedScrollingParentHelper nestedScrollingParentHelper; private boolean isBeingDragged; @DirectionRule private int swipeDir; private float oldY; private int lastOffsetY; private float touchSlop; private static final int DIR_TOP = 1; private static final int DIR_BOTTOM = -1; private static final int DIR_NULL = 0; @IntDef({DIR_TOP, DIR_BOTTOM, DIR_NULL}) private @interface DirectionRule {} public NestedScrollFrameLayout(Context context) { super(context); this.initialize(); } public NestedScrollFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); this.initialize(); } public NestedScrollFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.initialize(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public NestedScrollFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); this.initialize(); } private void initialize() { this.nestedScrollingChildHelper = new NestedScrollingChildHelper(this); this.nestedScrollingParentHelper = new NestedScrollingParentHelper(this); setNestedScrollingEnabled(true); this.touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: isBeingDragged = false; swipeDir = DIR_NULL; oldY = ev.getY(); lastOffsetY = 0; startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL); break; case MotionEvent.ACTION_MOVE: int deltaY = (int) (oldY - ev.getY() + lastOffsetY); if (!isBeingDragged) { if (Math.abs(deltaY) > touchSlop) { isBeingDragged = true; } else { swipeDir = DIR_NULL; oldY = ev.getY(); lastOffsetY = 0; } } if (isBeingDragged) { if (swipeDir == DIR_NULL || swipeDir * deltaY > 0 || (swipeDir * deltaY < 0 && Math.abs(deltaY) > touchSlop)) { int[] total = new int[] {0, deltaY}; int[] consumed = new int[] {0, 0}; int y = (int) (isParentOffset () ? ((View) getParent()).getY() : getY()); if (dispatchNestedPreScroll(total[0], total[1], consumed, null)) { total[0] -= consumed[0]; total[1] -= consumed[1]; } dispatchNestedScroll(consumed[0], consumed[1], total[0], total[1], null); swipeDir = deltaY == 0 ? DIR_NULL : (deltaY > 0 ? DIR_TOP : DIR_BOTTOM); oldY = ev.getY(); lastOffsetY = (int) (y - (isParentOffset () ? ((View) getParent()).getY() : getY())); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: isBeingDragged = false; stopNestedScroll(); break; } return true; } /** * If return true, the view will eliminate the error by compute the offset of it's parent view. * */ public abstract boolean isParentOffset(); // interface. // nested scrolling parent. @Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { startNestedScroll(nestedScrollAxes); return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; } @Override public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { nestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes); } @Override public void onStopNestedScroll(View target) { stopNestedScroll(); nestedScrollingParentHelper.onStopNestedScroll(target); } @Override public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, new int[] {0, 0}); } @Override public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { dispatchNestedPreScroll(dx, dy, consumed, new int[] {0, 0}); } @Override public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { return false; } @Override public boolean onNestedPreFling(View target, float velocityX, float velocityY) { return false; } @Override public int getNestedScrollAxes() { return nestedScrollingParentHelper.getNestedScrollAxes(); } // nested scrolling child. @Override public void setNestedScrollingEnabled(boolean enabled) { nestedScrollingChildHelper.setNestedScrollingEnabled(enabled); } @Override public boolean isNestedScrollingEnabled() { return nestedScrollingChildHelper.isNestedScrollingEnabled(); } @Override public boolean startNestedScroll(int axes) { return nestedScrollingChildHelper.startNestedScroll(axes); } @Override public void stopNestedScroll() { nestedScrollingChildHelper.stopNestedScroll(); } @Override public boolean hasNestedScrollingParent() { return nestedScrollingChildHelper.hasNestedScrollingParent(); } @Override public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { return nestedScrollingChildHelper.dispatchNestedScroll( dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); } @Override public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { return nestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); } @Override public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); } @Override public boolean dispatchNestedPreFling(float velocityX, float velocityY) { return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY); } }