Android實(shí)現(xiàn)越界回彈效果
本文實(shí)例為大家分享了Android實(shí)現(xiàn)越界回彈效果的具體代碼,供大家參考,具體內(nèi)容如下
1、直接上圖:
2、直接上代碼
public class DampingReboundLayout extends ViewGroup implements NestedScrollingParent3, ? ? ? ? NestedScrollingParent2, NestedScrollingChild3, NestedScrollingChild2, NestedScrollingParent, ? ? ? ? NestedScrollingChild { ? ? ? private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; ? ? private float DRAG_RATE = .35f; ? ? private ValueAnimator valueAnimator; ? ? ? public void setDragRate(int dragRate) { ? ? ? ? this.DRAG_RATE = dragRate; ? ? } ? ? ? ? // Default offset in dips from the top of the view to where the progress spinner should stop ? ? private static final int DEFAULT_CIRCLE_TARGET = 200; ? ? ? private View mTarget; // the target of the gesture ? ? ? // If nested scrolling is enabled, the total amount that needed to be ? ? // consumed by this as the nested scrolling parent is used in place of the ? ? // overscroll determined by MOVE events in the onTouch handler ? ? private float mTotalUnconsumed; ? ? private final NestedScrollingParentHelper mNestedScrollingParentHelper; ? ? private final NestedScrollingChildHelper mNestedScrollingChildHelper; ? ? private final int[] mParentScrollConsumed = new int[2]; ? ? private final int[] mParentOffsetInWindow = new int[2]; ? ? ? // Used for calls from old versions of onNestedScroll to v3 version of onNestedScroll. This only ? ? // exists to prevent GC costs that are present before API 21. ? ? private final int[] mNestedScrollingV2ConsumedCompat = new int[2]; ? ? private boolean mNestedScrollInProgress; ? ? ? ? private float mInitialScroll; ? ? ? // damping rebound orientation ? ? // ?0: horizontal ? ? // ?1: vertical ? ? private int dampingReboundOrientation = LinearLayoutCompat.HORIZONTAL; ? ? ? public void setOrientation(@LinearLayoutCompat.OrientationMode int orientation) { ? ? ? ? dampingReboundOrientation = orientation; ? ? } ? ? ? // Target is returning to its start offset because it was cancelled or a ? ? // refresh was triggered. ? ? private final DecelerateInterpolator mDecelerateInterpolator; ? ? private static final int[] LAYOUT_ATTRS = new int[]{ ? ? ? ? ? ? android.R.attr.enabled ? ? }; ? ? private int mLinearLayoutViewIndex = -1; ? ? ? ? /** ? ? ?* @see #setLegacyRequestDisallowInterceptTouchEventEnabled ? ? ?*/ ? ? private boolean mEnableLegacyRequestDisallowInterceptTouch; ? ? ? ? @Override ? ? protected void onDetachedFromWindow() { ? ? ? ? super.onDetachedFromWindow(); ? ? } ? ? ? ? /** ? ? ?* Simple constructor to use when creating a SwipeRefreshLayout from code. ? ? ?* ? ? ?* @param context ? ? ?*/ ? ? public DampingReboundLayout(@NonNull Context context) { ? ? ? ? this(context, null); ? ? } ? ? ? /** ? ? ?* Constructor that is called when inflating SwipeRefreshLayout from XML. ? ? ?* ? ? ?* @param context ? ? ?* @param attrs ? ? ?*/ ? ? public DampingReboundLayout(@NonNull Context context, @Nullable AttributeSet attrs) { ? ? ? ? this(context, attrs, 0); ? ? } ? ? ? public DampingReboundLayout(Context context, AttributeSet attrs, int defStyleAttr) { ? ? ? ? super(context, attrs, defStyleAttr); ? ? ? ? ? setWillNotDraw(false); ? ? ? ? mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR); ? ? ? ? ? final DisplayMetrics metrics = getResources().getDisplayMetrics(); ? ? ? ? ? setChildrenDrawingOrderEnabled(true); ? ? ? ? // the absolute offset has to take into account that the circle starts at an offset ? ? ? ? mNestedScrollingParentHelper = new NestedScrollingParentHelper(this); ? ? ? ? ? mNestedScrollingChildHelper = new NestedScrollingChildHelper(this); ? ? ? ? setNestedScrollingEnabled(true); ? ? ? ? ? final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); ? ? ? ? setEnabled(a.getBoolean(0, true)); ? ? ? ? a.recycle(); ? ? } ? ? ? @Override ? ? protected int getChildDrawingOrder(int childCount, int i) { ? ? ? ? if (mLinearLayoutViewIndex < 0) { ? ? ? ? ? ? return i; ? ? ? ? } else if (i == childCount - 1) { ? ? ? ? ? ? // Draw the selected child last ? ? ? ? ? ? return mLinearLayoutViewIndex; ? ? ? ? } else if (i >= mLinearLayoutViewIndex) { ? ? ? ? ? ? // Move the children after the selected child earlier one ? ? ? ? ? ? return i + 1; ? ? ? ? } else { ? ? ? ? ? ? // Keep the children before the selected child the same ? ? ? ? ? ? return i; ? ? ? ? } ? ? } ? ? ? ? private void ensureTarget() { ? ? ? ? // Don't bother getting the parent height if the parent hasn't been laid ? ? ? ? // out yet. ? ? ? ? if (mTarget == null) { ? ? ? ? ? ? mTarget = getChildAt(0); ? ? ? ? } ? ? } ? ? ? ? @Override ? ? protected void onLayout(boolean changed, int left, int top, int right, int bottom) { ? ? ? ? final int width = getMeasuredWidth(); ? ? ? ? final int height = getMeasuredHeight(); ? ? ? ? if (getChildCount() == 0) { ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? if (mTarget == null) { ? ? ? ? ? ? ensureTarget(); ? ? ? ? } ? ? ? ? if (mTarget == null) { ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? final View child = mTarget; ? ? ? ? final int childLeft = getPaddingLeft(); ? ? ? ? final int childTop = getPaddingTop(); ? ? ? ? final int childWidth = width - getPaddingLeft() - getPaddingRight(); ? ? ? ? final int childHeight = height - getPaddingTop() - getPaddingBottom(); ? ? ? ? child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); ? ? } ? ? ? @Override ? ? public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ? ? ? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec); ? ? ? ? if (mTarget == null) { ? ? ? ? ? ? ensureTarget(); ? ? ? ? } ? ? ? ? if (mTarget == null) { ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? mTarget.measure(MeasureSpec.makeMeasureSpec( ? ? ? ? ? ? ? ? getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), ? ? ? ? ? ? ? ? MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( ? ? ? ? ? ? ? ? getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)); ? ? } ? ? ? /** ? ? ?* @return Whether it is possible for the child view of this layout to ? ? ?* scroll up. Override this if the child view is a custom view. ? ? ?*/ ? ? public boolean canChildScrollUp() { ? ? ? ? if (mTarget instanceof ListView) { ? ? ? ? ? ? return ListViewCompat.canScrollList((ListView) mTarget, -1); ? ? ? ? } ? ? ? ? return dampingReboundOrientation == 1 ? mTarget.canScrollVertically(-1) : mTarget.canScrollHorizontally(-1); ? ? } ? ? ? public boolean canChildScrollDown() { ? ? ? ? if (mTarget instanceof ListView) { ? ? ? ? ? ? return ListViewCompat.canScrollList((ListView) mTarget, 1); ? ? ? ? } ? ? ? ? return dampingReboundOrientation == 1 ? mTarget.canScrollVertically(1) : mTarget.canScrollHorizontally(1); ? ? } ? ? ? ? @Override ? ? public boolean onInterceptTouchEvent(MotionEvent ev) { ? ? ? ? ensureTarget(); ? ? ? ? final int action = ev.getActionMasked(); ? ? ? ? int pointerIndex; ? ? ? ? ? if (!isEnabled() || canChildScrollUp() || canChildScrollDown() || mNestedScrollInProgress) { ? ? ? ? ? ? // Fail fast if we're not in a state where a swipe is possible ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? ? switch (action) { ? ? ? ? ? ? case MotionEvent.ACTION_DOWN: ? ? ? ? ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? ? ? ? ? mInitialScroll = ev.getY(); ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? mInitialScroll = ev.getX(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? case MotionEvent.ACTION_MOVE: ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? case MotionEvent.ACTION_UP: ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL: ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? default: ? ? ? ? } ? ? ? ? return super.onInterceptTouchEvent(ev); ? ? } ? ? ? /** ? ? ?* Enables the legacy behavior of {@link #requestDisallowInterceptTouchEvent} from before ? ? ?* 1.1.0-alpha03, where the request is neither honored, nor propagated up to its parents, ? ? ?* in either of the following two cases: ? ? ?* <ul> ? ? ?* ? ? <li>The child as an {@link AbsListView} and the runtime is API < 21</li> ? ? ?* ? ? <li>The child has nested scrolling disabled</li> ? ? ?* </ul> ? ? ?* Use this method <em>only</em> if your application: ? ? ?* <ul> ? ? ?* ? ? <li>is upgrading SwipeRefreshLayout from < 1.1.1 to >= 1.1.0-alpha03</li> ? ? ?* ? ? <li>has a SwipeRefreshLayout, or its parent, that no longer responds to touch events ? ? ?* ? ? when it should</li> ? ? ?* ? ? <li>setting this method to {@code true} fixes that issue</li> ? ? ?* </ul> ? ? ?* ? ? ?* @param enabled {@code true} to enable the legacy behavior, {@code false} for default behavior ? ? ?* @deprecated Only use this method if the changes introduced in ? ? ?* {@link #requestDisallowInterceptTouchEvent} in version 1.1.0-alpha03 and 1.1.1 ? ? ?* are breaking your application. ? ? ?*/ ? ? @Deprecated ? ? public void setLegacyRequestDisallowInterceptTouchEventEnabled(boolean enabled) { ? ? ? ? mEnableLegacyRequestDisallowInterceptTouch = enabled; ? ? } ? ? ? @Override ? ? public void requestDisallowInterceptTouchEvent(boolean b) { ? ? ? ? if (mEnableLegacyRequestDisallowInterceptTouch ? ? ? ? ? ? ? ? && ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView) ? ? ? ? ? ? ? ? || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget)))) { ? ? ? ? ? ? // Legacy behavior: if this is a List < L or another view that doesn't support ? ? ? ? ? ? // nested scrolling, ignore this request so that the vertical scroll event ? ? ? ? ? ? // isn't stolen ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? super.requestDisallowInterceptTouchEvent(b); ? ? } ? ? ? // NestedScrollingParent 3 ? ? ? @Override ? ? public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int dxUnconsumed, int dyUnconsumed, @ViewCompat.NestedScrollType int type, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@NonNull int[] consumed) { ? ? ? ? if (type != ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? ? int consumedBeforeParents = dampingReboundOrientation == 1 ? consumed[1] : consumed[0]; ? ? ? ? dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, ? ? ? ? ? ? ? ? mParentOffsetInWindow, type, consumed); ? ? ? ? int consumedByParents = (dampingReboundOrientation == 1 ? consumed[1] : consumed[0]) - consumedBeforeParents; ? ? ? ? int unconsumedAfterParents = dampingReboundOrientation == 1 ? dyUnconsumed : dxUnconsumed - consumedByParents; ? ? ? ? ? // There are two reasons why scroll distance may be totally consumed. ?1) All of the nested ? ? ? ? // scrolling parents up the hierarchy implement NestedScrolling3 and consumed all of the ? ? ? ? // distance or 2) at least 1 nested scrolling parent doesn't implement NestedScrolling3 and ? ? ? ? // for comparability reasons, we are supposed to act like they have. ? ? ? ? // ? ? ? ? // We must assume 2) is the case because we have no way of determining that it isn't, and ? ? ? ? // therefore must fallback to a previous hack that was done before nested scrolling 3 ? ? ? ? // existed. ? ? ? ? int remainingDistanceToScroll; ? ? ? ? if (unconsumedAfterParents == 0) { ? ? ? ? ? ? // The previously implemented hack is to see how far we were offset and assume that that ? ? ? ? ? ? // distance is equal to how much all of our parents consumed. ? ? ? ? ? ? remainingDistanceToScroll = dampingReboundOrientation == 1 ? (dyUnconsumed + mParentOffsetInWindow[1]) : dxUnconsumed + mParentOffsetInWindow[0]; ? ? ? ? } else { ? ? ? ? ? ? remainingDistanceToScroll = unconsumedAfterParents; ? ? ? ? } ? ? ? ? ? ? // Not sure why we have to make sure the child can't scroll up... but seems dangerous to ? ? ? ? // remove. ? ? ? ? if (remainingDistanceToScroll < 0 && !canChildScrollUp()) { ? ? ? ? ? ? mTotalUnconsumed += Math.abs(remainingDistanceToScroll); ? ? ? ? ? ? moveSpinner(mTotalUnconsumed); ? ? ? ? ? ? // If we've gotten here, we need to consume whatever is left to consume, which at this ? ? ? ? ? ? // point is either equal to 0, or remainingDistanceToScroll. ? ? ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? ? ? consumed[1] += unconsumedAfterParents; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? consumed[0] += unconsumedAfterParents; ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? ? if (remainingDistanceToScroll > 0 && !canChildScrollDown()) { ? ? ? ? ? ? mTotalUnconsumed -= Math.abs(remainingDistanceToScroll); ? ? ? ? ? ? moveSpinner(mTotalUnconsumed); ? ? ? ? ? ? // If we've gotten here, we need to consume whatever is left to consume, which at this ? ? ? ? ? ? // point is either equal to 0, or remainingDistanceToScroll. ? ? ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? ? ? consumed[1] -= unconsumedAfterParents; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? consumed[0] -= unconsumedAfterParents; ? ? ? ? ? ? } ? ? ? ? ? } ? ? } ? ? ? // NestedScrollingParent 2 ? ? ? @Override ? ? public boolean onStartNestedScroll(View child, View target, int axes, int type) { ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? return onStartNestedScroll(child, target, axes); ? ? ? ? } else { ? ? ? ? ? ? return false; ? ? ? ? } ? ? } ? ? ? @Override ? ? public void onNestedScrollAccepted(View child, View target, int axes, int type) { ? ? ? ? // Should always be true because onStartNestedScroll returns false for all type != ? ? ? ? // ViewCompat.TYPE_TOUCH, but check just in case. ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? onNestedScrollAccepted(child, target, axes); ? ? ? ? } ? ? } ? ? ? @Override ? ? public void onStopNestedScroll(View target, int type) { ? ? ? ? // Should always be true because onStartNestedScroll returns false for all type != ? ? ? ? // ViewCompat.TYPE_TOUCH, but check just in case. ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? onStopNestedScroll(target); ? ? ? ? } ? ? } ? ? ? @Override ? ? public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int dyUnconsumed, int type) { ? ? ? ? onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, ? ? ? ? ? ? ? ? mNestedScrollingV2ConsumedCompat); ? ? } ? ? ? @Override ? ? public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int type) { ? ? ? ? // Should always be true because onStartNestedScroll returns false for all type != ? ? ? ? // ViewCompat.TYPE_TOUCH, but check just in case. ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? onNestedPreScroll(target, dx, dy, consumed); ? ? ? ? } ? ? } ? ? ? // NestedScrollingParent 1 ? ? ? @Override ? ? public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { ? ? ? ? return isEnabled() && dampingReboundOrientation == 1 ? (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 1 : (nestedScrollAxes & ViewCompat.SCROLL_AXIS_HORIZONTAL) != 2; ? ? } ? ? ? @Override ? ? public void onNestedScrollAccepted(View child, View target, int axes) { ? ? ? ? // Reset the counter of how much leftover scroll needs to be consumed. ? ? ? ? mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes); ? ? ? ? // Dispatch up to the nested parent ? ? ? ? startNestedScroll(axes & (dampingReboundOrientation == 1 ? ViewCompat.SCROLL_AXIS_VERTICAL : ViewCompat.SCROLL_AXIS_HORIZONTAL)); ? ? ? ? mTotalUnconsumed = 0; ? ? ? ? mNestedScrollInProgress = true; ? ? } ? ? ? @Override ? ? public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { ? ? ? ? // If we are in the middle of consuming, a scroll, then we want to move the spinner back up ? ? ? ? // before allowing the list to scroll ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? if (dy > 0 && mTotalUnconsumed > 0 || dy < 0 && mTotalUnconsumed < 0) { ? ? ? ? ? ? ? ? if (dy > mTotalUnconsumed) { ? ? ? ? ? ? ? ? ? ? consumed[1] = (int) mTotalUnconsumed; ? ? ? ? ? ? ? ? ? ? mTotalUnconsumed = 0; ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? mTotalUnconsumed -= dy; ? ? ? ? ? ? ? ? ? ? consumed[1] = dy; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? moveSpinner(mTotalUnconsumed); ? ? ? ? ? ? } ? ? ? ? } else { ? ? ? ? ? ? if (dx > 0 && mTotalUnconsumed > 0 || dx < 0 && mTotalUnconsumed < 0) { ? ? ? ? ? ? ? ? if (dx > mTotalUnconsumed) { ? ? ? ? ? ? ? ? ? ? consumed[0] = (int) mTotalUnconsumed; ? ? ? ? ? ? ? ? ? ? mTotalUnconsumed = 0; ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? mTotalUnconsumed -= dx; ? ? ? ? ? ? ? ? ? ? consumed[0] = dx; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? moveSpinner(mTotalUnconsumed); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? ? ? // If a client layout is using a custom start position for the circle ? ? ? ? // view, they mean to hide it again before scrolling the child view ? ? ? ? // If we get back to mTotalUnconsumed == 0 and there is more to go, hide ? ? ? ? // the circle so it isn't exposed if its blocking content is moved ? ? ? ? ? // Now let our nested parent consume the leftovers ? ? ? ? final int[] parentConsumed = mParentScrollConsumed; ? ? ? ? if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) { ? ? ? ? ? ? consumed[0] += parentConsumed[0]; ? ? ? ? ? ? consumed[1] += parentConsumed[1]; ? ? ? ? } ? ? } ? ? ? @Override ? ? public int getNestedScrollAxes() { ? ? ? ? return mNestedScrollingParentHelper.getNestedScrollAxes(); ? ? } ? ? ? @Override ? ? public void onStopNestedScroll(View target) { ? ? ? ? mNestedScrollingParentHelper.onStopNestedScroll(target); ? ? ? ? mNestedScrollInProgress = false; ? ? ? ? // Finish the spinner for nested scrolling if we ever consumed any ? ? ? ? // unconsumed nested scroll ? ? ? ? if (mTotalUnconsumed != 0) { ? ? ? ? ? ? finishSpinner(); ? ? ? ? ? ? mTotalUnconsumed = 0; ? ? ? ? } ? ? ? ? // Dispatch up our nested parent ? ? ? ? stopNestedScroll(); ? ? } ? ? ? @Override ? ? public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?final int dxUnconsumed, final int dyUnconsumed) { ? ? ? ? onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, ? ? ? ? ? ? ? ? ViewCompat.TYPE_TOUCH, mNestedScrollingV2ConsumedCompat); ? ? } ? ? ? @Override ? ? public boolean onNestedPreFling(View target, float velocityX, float velocityY) { ? ? ? ? return dispatchNestedPreFling(velocityX, velocityY); ? ? } ? ? ? @Override ? ? public boolean onNestedFling(View target, float velocityX, float velocityY, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean consumed) { ? ? ? ? return dispatchNestedFling(velocityX, velocityY, consumed); ? ? } ? ? ? // NestedScrollingChild 3 ? ? ? @Override ? ? public void dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int dyUnconsumed, @Nullable int[] offsetInWindow, @ViewCompat.NestedScrollType int type, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@NonNull int[] consumed) { ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, ? ? ? ? ? ? ? ? ? ? dyUnconsumed, offsetInWindow, type, consumed); ? ? ? ? } ? ? } ? ? ? // NestedScrollingChild 2 ? ? ? @Override ? ? public boolean startNestedScroll(int axes, int type) { ? ? ? ? return type == ViewCompat.TYPE_TOUCH && startNestedScroll(axes); ? ? } ? ? ? @Override ? ? public void stopNestedScroll(int type) { ? ? ? ? if (type == ViewCompat.TYPE_TOUCH) { ? ? ? ? ? ? stopNestedScroll(); ? ? ? ? } ? ? } ? ? ? @Override ? ? public boolean hasNestedScrollingParent(int type) { ? ? ? ? return type == ViewCompat.TYPE_TOUCH && hasNestedScrollingParent(); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int dyUnconsumed, int[] offsetInWindow, int type) { ? ? ? ? return type == ViewCompat.TYPE_TOUCH && mNestedScrollingChildHelper.dispatchNestedScroll( ? ? ? ? ? ? ? ? dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int type) { ? ? ? ? return type == ViewCompat.TYPE_TOUCH && dispatchNestedPreScroll(dx, dy, consumed, ? ? ? ? ? ? ? ? offsetInWindow); ? ? } ? ? ? // NestedScrollingChild 1 ? ? ? @Override ? ? public void setNestedScrollingEnabled(boolean enabled) { ? ? ? ? mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled); ? ? } ? ? ? @Override ? ? public boolean isNestedScrollingEnabled() { ? ? ? ? return mNestedScrollingChildHelper.isNestedScrollingEnabled(); ? ? } ? ? ? @Override ? ? public boolean startNestedScroll(int axes) { ? ? ? ? return mNestedScrollingChildHelper.startNestedScroll(axes); ? ? } ? ? ? @Override ? ? public void stopNestedScroll() { ? ? ? ? mNestedScrollingChildHelper.stopNestedScroll(); ? ? } ? ? ? @Override ? ? public boolean hasNestedScrollingParent() { ? ? ? ? return mNestedScrollingChildHelper.hasNestedScrollingParent(); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int dyUnconsumed, int[] offsetInWindow) { ? ? ? ? return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, ? ? ? ? ? ? ? ? dxUnconsumed, dyUnconsumed, offsetInWindow); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { ? ? ? ? return mNestedScrollingChildHelper.dispatchNestedPreScroll( ? ? ? ? ? ? ? ? dx, dy, consumed, offsetInWindow); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { ? ? ? ? return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); ? ? } ? ? ? @Override ? ? public boolean dispatchNestedPreFling(float velocityX, float velocityY) { ? ? ? ? return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY); ? ? } ? ? ? ? private void moveSpinner(float overScrollTop) { ? ? ? ? float scroll = overScrollTop * DRAG_RATE; ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? if (scroll > getHeight() / 2f) { ? ? ? ? ? ? ? ? scroll = getHeight() / 2f; ? ? ? ? ? ? } ? ? ? ? ? ? if (scroll < -getHeight() / 2f) { ? ? ? ? ? ? ? ? scroll = -getHeight() / 2f; ? ? ? ? ? ? } ? ? ? ? ? ? mTarget.setTranslationY(scroll); ? ? ? ? } else { ? ? ? ? ? ? if (scroll > getWidth() / 2f) { ? ? ? ? ? ? ? ? scroll = getWidth() / 2f; ? ? ? ? ? ? } ? ? ? ? ? ? if (scroll < -getWidth() / 2f) { ? ? ? ? ? ? ? ? scroll = -getWidth() / 2f; ? ? ? ? ? ? } ? ? ? ? ? ? mTarget.setTranslationX(scroll); ? ? ? ? } ? ? ? ? } ? ? ? ? private void finishSpinner() { ? ? ? ? animateOffsetToStartPosition(); ? ? } ? ? ? ? private void animateOffsetToStartPosition() { ? ? ? ? valueAnimator = ValueAnimator.ofFloat(dampingReboundOrientation == 1 ? mTarget.getTranslationY() : mTarget.getTranslationX(), 0); ? ? ? ? valueAnimator.setDuration(500); ? ? ? ? valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { ? ? ? ? ? ? @Override ? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator animation) { ? ? ? ? ? ? ? ? if (mTarget != null && animation != null) { ? ? ? ? ? ? ? ? ? ? if (dampingReboundOrientation == 1) { ? ? ? ? ? ? ? ? ? ? ? ? mTarget.setTranslationY((Float) animation.getAnimatedValue()); ? ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ? mTarget.setTranslationX((Float) animation.getAnimatedValue()); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? }); ? ? ? ? valueAnimator.setInterpolator(mDecelerateInterpolator); ? ? ? ? valueAnimator.start(); ? ? } ? ? ? ? @Override ? ? public boolean onTouchEvent(MotionEvent ev) { ? ? ? ? final int action = ev.getActionMasked(); ? ? ? ? int pointerIndex = -1; ? ? ? ? if (!isEnabled() || canChildScrollUp() || canChildScrollDown() || mNestedScrollInProgress) { ? ? ? ? ? ? // Fail fast if we're not in a state where a swipe is possible ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? switch (action) { ? ? ? ? ? ? case MotionEvent.ACTION_DOWN: ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? case MotionEvent.ACTION_MOVE: { ? ? ? ? ? ? ? ? final float y = ev.getY(); ? ? ? ? ? ? ? ? final float overScrollTop = (y - mInitialScroll); ? ? ? ? ? ? ? ? // While the spinner is being dragged down, our parent shouldn't try ? ? ? ? ? ? ? ? // to intercept touch events. It will stop the drag gesture abruptly. ? ? ? ? ? ? ? ? getParent().requestDisallowInterceptTouchEvent(true); ? ? ? ? ? ? ? ? moveSpinner(overScrollTop); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? ? ? case MotionEvent.ACTION_UP: { ? ? ? ? ? ? ? ? finishSpinner(); ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL: ? ? ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? ? return true; ? ? } ? }
3、設(shè)置
①阻尼距離:setDragRate() 設(shè)置阻尼效果比例,阻尼距離根據(jù)控件寬高*DRAG_RATE
②設(shè)置阻尼方向:setOrientation(@LinearLayoutCompat.OrientationMode int orientation)
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)橡皮筋回彈和平移縮放效果
- Android自定義View實(shí)現(xiàn)豎向滑動(dòng)回彈效果
- android實(shí)現(xiàn)可上下回彈的scrollview
- Android實(shí)現(xiàn)回彈ScrollView的原理
- Android自定義實(shí)現(xiàn)可回彈的ScollView
- Android自定義ScrollView實(shí)現(xiàn)阻尼回彈
- Android自定義scrollview實(shí)現(xiàn)回彈效果
- Android ScrollView的頂部下拉和底部上拉回彈效果
- Android RecyclerView上拉加載更多功能回彈實(shí)現(xiàn)代碼
- Android實(shí)現(xiàn)背景圖滑動(dòng)變大松開回彈效果
相關(guān)文章
Android 使用AsyncTask實(shí)現(xiàn)斷點(diǎn)續(xù)傳
這篇文章主要介紹了Android 使用AsyncTask實(shí)現(xiàn)斷點(diǎn)續(xù)傳的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05Android6.0編程實(shí)現(xiàn)雙向通話自動(dòng)錄音功能的方法詳解
這篇文章主要介紹了Android6.0編程實(shí)現(xiàn)雙向通話自動(dòng)錄音功能的方法,結(jié)合實(shí)例形式分析了Android錄音功能的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07如何使用Android實(shí)現(xiàn)接口實(shí)信息在留言板顯示
這篇文章主要介紹了如何使用Android接口實(shí)現(xiàn)信息的留言板顯示,需要的朋友可以參考下2015-07-07Android小程序?qū)崿F(xiàn)選項(xiàng)菜單
這篇文章主要為大家詳細(xì)介紹了Android小程序?qū)崿F(xiàn)選項(xiàng)菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Android項(xiàng)目開發(fā)常用工具類LightTaskUtils源碼介紹
LightTaskUtils是一個(gè)輕量級(jí)的線程管理工具,本文通過實(shí)例代碼給大家詳細(xì)介紹Android項(xiàng)目開發(fā)常用工具類LightTaskUtils的相關(guān)知識(shí),感興趣的朋友一起看看吧2022-06-06