This example shares the specific code for Android custom view to achieve sliding rebound for your reference. The specific content is as follows
Preface
The rebound effect of Android page sliding
1. Key code
public class UniversalBounceView extends FrameLayout implements IPull { private static final String TAG = "UniversalBounceView"; //default. private static final int SCROLL_DURATION = 200; private static final float SCROLL_FRACTION = 0.4f; private static final int VIEW_TYPE_NORMAL = 0; private static final int VIEW_TYPE_ABSLISTVIEW = 1; private static final int VIEW_TYPE_SCROLLVIEW = 2; private static float VIEW_SCROLL_MAX = 720; private int viewHeight; private AbsListView alv; private OnBounceStateListener onBounceStateListener; private View child; private Scroller scroller; private boolean pullEnabled = true; private boolean pullPaused; private int touchSlop = 8; private int mPointerId; private float downY, lastDownY, tmpY; private int lastPointerIndex; private float moveDiffY; private boolean isNotJustInClickMode; private int moveDelta; private int viewType = VIEW_TYPE_NORMAL; public UniversalBounceView(Context context) { super(context); init(context); } public UniversalBounceView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public UniversalBounceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { scroller = new Scroller(context, new CustomDecInterpolator()); touchSlop = (int) ((context).getScaledTouchSlop() * 1.5); } class CustomDecInterpolator extends DecelerateInterpolator { public CustomDecInterpolator() { super(); } public CustomDecInterpolator(float factor) { super(factor); } public CustomDecInterpolator(Context context, AttributeSet attrs) { super(context, attrs); } @Override public float getInterpolation(float input) { return (float) (input, 6.0 / 12); } } private void checkCld() { int cnt = getChildCount(); if (1 <= cnt) { child = getChildAt(0); } else if (0 == cnt) { pullEnabled = false; child = new View(getContext()); } else { throw new ArrayIndexOutOfBoundsException("child count can not be less than 0."); } } @Override protected void onFinishInflate() { checkCld(); (); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { (w, h, oldw, oldh); viewHeight = h; VIEW_SCROLL_MAX = h * 1 / 3; } private boolean isTouch = true; public void setTouch(boolean isTouch) { = isTouch; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!isTouch) { return true; } else { try { if (isPullEnable()) { if (() == MotionEvent.ACTION_MOVE) { if ((() - tmpY) < touchSlop) { return (ev); } else { tmpY = Integer.MIN_VALUE; } } return takeEvent(ev); } } catch (IllegalArgumentException | IllegalStateException e) { (); } if (getVisibility() != ) { return true; } return (ev); } } private boolean takeEvent(MotionEvent ev) { int action = (); switch (action) { case MotionEvent.ACTION_DOWN: mPointerId = (0); downY = (); tmpY = downY; (()); setScrollY(()); (); pullPaused = true; isNotJustInClickMode = false; moveDelta = 0; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: pullPaused = false; smoothScrollTo(0); if (isNotJustInClickMode) { (MotionEvent.ACTION_CANCEL); } postDelayed(new Runnable() { @Override public void run() { if (getScrollY() == 0 && onBounceStateListener != null) { (); } } }, 200); break; case MotionEvent.ACTION_MOVE: lastPointerIndex = (mPointerId); lastDownY = (lastPointerIndex); moveDiffY = ((lastDownY - downY) * getScrollFraction()); downY = lastDownY; boolean canStart = isCanPullStart(); boolean canEnd = isCanPullEnd(); int scroll = getScrollY(); float total = scroll - moveDiffY; if (canScrollInternal(scroll, canStart, canEnd)) { handleInternal(); break; } if ((scroll) > VIEW_SCROLL_MAX) { return true; } if ((canStart && total < 0) || (canEnd && total > 0)) { if (moveDelta < touchSlop) { moveDelta += (moveDiffY); } else { isNotJustInClickMode = true; } if (onBounceStateListener != null) { (); } scrollBy(0, (int) -moveDiffY); return true; } // else if ((total > 0 && canStart) || (total < 0 && canEnd)) { // if (moveDelta < touchSlop) { // moveDelta += (moveDiffY); // } else { // isNotJustInClickMode = true; // } // scrollBy(0, -scroll); // return true; // } break; case MotionEvent.ACTION_POINTER_UP: handlePointerUp(ev, 1); break; default: break; } return (ev); } private boolean canScrollInternal(int scroll, boolean canStart, boolean canEnd) { boolean result = false; if ((child instanceof RecyclerView) || (child instanceof AbsListView) || child instanceof ScrollView) { viewType = VIEW_TYPE_ABSLISTVIEW; result = canStart && canEnd; } else if (child instanceof ScrollView || child instanceof NestedScrollView) { viewType = VIEW_TYPE_SCROLLVIEW; } else { return false; } if (result) { isNotJustInClickMode = true; if (moveDelta < touchSlop) { moveDelta += (moveDiffY); return true; } return false; } if (((scroll == 0 && canStart && moveDiffY < 0) || (scroll == 0 && canEnd && moveDiffY > 0) || (!canStart && !canEnd))) { return true; } if (moveDelta < touchSlop) { moveDelta += (moveDiffY); return true; } else { isNotJustInClickMode = true; } return false; } private void handleInternal() { } private void handlePointerUp(MotionEvent event, int type) { int pointerIndexLeave = (); int pointerIdLeave = (pointerIndexLeave); if (mPointerId == pointerIdLeave) { int reIndex = pointerIndexLeave == 0 ? 1 : 0; mPointerId = (reIndex); // Adjust the touch position to prevent jumps downY = (reIndex); } } @Override public boolean onTouchEvent(MotionEvent event) { return (event); } private void smoothScrollTo(int value) { int scroll = getScrollY(); (0, scroll, 0, value - scroll, SCROLL_DURATION); postInvalidate(); } @Override public void computeScroll() { (); if (!pullPaused && ()) { scrollTo((), ()); postInvalidate(); } } private float getScrollFraction() { float ratio = (getScrollY()) / VIEW_SCROLL_MAX; ratio = ratio < 1 ? ratio : 1; float fraction = (float) (-2 * ((ratio + 1) * ) / 5.0f) + 0.1f; return fraction < 0.10f ? 0.10f : fraction; } @Override public boolean isPullEnable() { return pullEnabled; } @Override public boolean isCanPullStart() { if (child instanceof RecyclerView) { RecyclerView recyclerView = (RecyclerView) child; return !(-1); } if (child instanceof AbsListView) { AbsListView lv = (AbsListView) child; return !(-1); } if (child instanceof RelativeLayout || child instanceof FrameLayout || child instanceof LinearLayout || child instanceof WebView || child instanceof View) { return () == 0; } return false; } @Override public boolean isCanPullEnd() { if (child instanceof RecyclerView) { RecyclerView recyclerView = (RecyclerView) child; return !(1); } if (child instanceof AbsListView) { AbsListView lv = (AbsListView) child; int first = (); int last = (); View view = (last - first); if (null == view) { return false; } else { return (() - 1 == last) && (() <= ()); } } if (child instanceof ScrollView) { View v = ((ScrollView) child).getChildAt(0); if (null == v) { return true; } else { return () >= () - (); } } if (child instanceof NestedScrollView) { View v = ((NestedScrollView) child).getChildAt(0); if (null == v) { return true; } else { return () >= () - (); } } if (child instanceof WebView) { return (((WebView) child).getContentHeight() * ((WebView) child).getScale()) - (((WebView) child).getHeight() + ((WebView) child).getScrollY()) <= 10; } if (child instanceof RelativeLayout || child instanceof FrameLayout || child instanceof LinearLayout || child instanceof View) { return (() == 0); } return false; } /** * Achieve effect rebound effect through addView * * @param replaceChildView View that needs to be replaced */ public void replaceAddChildView(View replaceChildView) { if (replaceChildView != null) { removeAllViews(); child = replaceChildView; addView(replaceChildView); } } public void setPullEnabled(boolean enable) { pullEnabled = enable; } public interface OnBounceStateListener { public void onBounce(); public void overBounce(); } public void setOnBounceStateListener(OnBounceStateListener onBounceStateListener) { = onBounceStateListener; } @Override public boolean dispatchKeyEvent(KeyEvent event) { try { return (event); } catch (IllegalArgumentException | IllegalStateException e) { (); } return false; } @Override public void dispatchWindowFocusChanged(boolean hasFocus) { try { (hasFocus); } catch (IllegalArgumentException | IllegalStateException e) { (); } } }
2. Pay attention to the key points
Prevent animation shaking when the slide ends
private void handlePointerUp(MotionEvent event, int type) { int pointerIndexLeave = (); int pointerIdLeave = (pointerIndexLeave); if (mPointerId == pointerIdLeave) { int reIndex = pointerIndexLeave == 0 ? 1 : 0; mPointerId = (reIndex); // Adjust the touch position to prevent jumps downY = (reIndex); } }
Summarize
The above is the main content of the article, which achieves the effect of vertical sliding rebound.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.