温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android怎么自定义View实现竖向滑动回弹效果

发布时间:2022-04-18 16:54:48 来源:亿速云 阅读:212 作者:iii 栏目:开发技术

这篇文章主要介绍“Android怎么自定义View实现竖向滑动回弹效果”,在日常操作中,相信很多人在Android怎么自定义View实现竖向滑动回弹效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android怎么自定义View实现竖向滑动回弹效果”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、关键代码

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) (ViewConfiguration.get(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) Math.pow(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();         super.onFinishInflate();     }       @Override     protected void onSizeChanged(int w, int h, int oldw, int oldh) {         super.onSizeChanged(w, h, oldw, oldh);         viewHeight = h;         VIEW_SCROLL_MAX = h * 1 / 3;     }       private boolean isTouch = true;       public void setTouch(boolean isTouch) {         this.isTouch = isTouch;     }       @Override     public boolean dispatchTouchEvent(MotionEvent ev) {         if (!isTouch) {             return true;         } else {             try {                 if (isPullEnable()) {                     if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {                         if (Math.abs(ev.getY() - tmpY) < touchSlop) {                             return super.dispatchTouchEvent(ev);                         } else {                             tmpY = Integer.MIN_VALUE;                         }                     }                     return takeEvent(ev);                 }             } catch (IllegalArgumentException | IllegalStateException e) {                 e.printStackTrace();             }             if (getVisibility() != View.VISIBLE) {                 return true;             }             return super.dispatchTouchEvent(ev);         }     }       private boolean takeEvent(MotionEvent ev) {         int action = ev.getActionMasked();         switch (action) {             case MotionEvent.ACTION_DOWN:                 mPointerId = ev.getPointerId(0);                 downY = ev.getY();                 tmpY = downY;                 scroller.setFinalY(scroller.getCurrY());                 setScrollY(scroller.getCurrY());                 scroller.abortAnimation();                 pullPaused = true;                 isNotJustInClickMode = false;                 moveDelta = 0;                 break;             case MotionEvent.ACTION_UP:             case MotionEvent.ACTION_CANCEL:                 pullPaused = false;                 smoothScrollTo(0);                 if (isNotJustInClickMode) {                     ev.setAction(MotionEvent.ACTION_CANCEL);                 }                 postDelayed(new Runnable() {                     @Override                     public void run() {                         if (getScrollY() == 0 && onBounceStateListener != null) {                             onBounceStateListener.overBounce();                         }                     }                 }, 200);                 break;             case MotionEvent.ACTION_MOVE:                 lastPointerIndex = ev.findPointerIndex(mPointerId);                 lastDownY = ev.getY(lastPointerIndex);                 moveDiffY = Math.round((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 (Math.abs(scroll) > VIEW_SCROLL_MAX) {                     return true;                 }                 if ((canStart && total < 0) || (canEnd && total > 0)) {                     if (moveDelta < touchSlop) {                         moveDelta += Math.abs(moveDiffY);                     } else {                         isNotJustInClickMode = true;                     }                     if (onBounceStateListener != null) {                         onBounceStateListener.onBounce();                     }                     scrollBy(0, (int) -moveDiffY);                     return true;                 } //                else if ((total > 0 && canStart) || (total < 0 && canEnd)) { //                    if (moveDelta < touchSlop) { //                        moveDelta += Math.abs(moveDiffY); //                    } else { //                        isNotJustInClickMode = true; //                    } //                    scrollBy(0, -scroll); //                    return true; //                }                 break;             case MotionEvent.ACTION_POINTER_UP:                 handlePointerUp(ev, 1);                 break;             default:                 break;         }         return super.dispatchTouchEvent(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 += Math.abs(moveDiffY);                 return true;             }             return false;         }         if (((scroll == 0 && canStart && moveDiffY < 0) || (scroll == 0 && canEnd && moveDiffY > 0) || (!canStart && !canEnd))) {             return true;         }         if (moveDelta < touchSlop) {             moveDelta += Math.abs(moveDiffY);             return true;         } else {             isNotJustInClickMode = true;         }         return false;     }       private void handleInternal() {       }       private void handlePointerUp(MotionEvent event, int type) {         int pointerIndexLeave = event.getActionIndex();         int pointerIdLeave = event.getPointerId(pointerIndexLeave);         if (mPointerId == pointerIdLeave) {             int reIndex = pointerIndexLeave == 0 ? 1 : 0;             mPointerId = event.getPointerId(reIndex);             // 调整触摸位置,防止出现跳动             downY = event.getY(reIndex);         }     }       @Override     public boolean onTouchEvent(MotionEvent event) {         return super.onTouchEvent(event);     }       private void smoothScrollTo(int value) {         int scroll = getScrollY();         scroller.startScroll(0, scroll, 0, value - scroll, SCROLL_DURATION);         postInvalidate();     }       @Override     public void computeScroll() {         super.computeScroll();         if (!pullPaused && scroller.computeScrollOffset()) {             scrollTo(scroller.getCurrX(), scroller.getCurrY());             postInvalidate();         }     }       private float getScrollFraction() {         float ratio = Math.abs(getScrollY()) / VIEW_SCROLL_MAX;         ratio = ratio < 1 ? ratio : 1;         float fraction = (float) (-2 * Math.cos((ratio + 1) * Math.PI) / 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 !recyclerView.canScrollVertically(-1);         }         if (child instanceof AbsListView) {             AbsListView lv = (AbsListView) child;             return !lv.canScrollVertically(-1);         }         if (child instanceof RelativeLayout                 || child instanceof FrameLayout                 || child instanceof LinearLayout                 || child instanceof WebView                 || child instanceof View) {             return child.getScrollY() == 0;         }         return false;     }       @Override     public boolean isCanPullEnd() {         if (child instanceof RecyclerView) {             RecyclerView recyclerView = (RecyclerView) child;             return !recyclerView.canScrollVertically(1);         }         if (child instanceof AbsListView) {             AbsListView lv = (AbsListView) child;             int first = lv.getFirstVisiblePosition();             int last = lv.getLastVisiblePosition();             View view = lv.getChildAt(last - first);             if (null == view) {                 return false;             } else {                 return (lv.getCount() - 1 == last) &&                         (view.getBottom() <= lv.getHeight());             }         }         if (child instanceof ScrollView) {             View v = ((ScrollView) child).getChildAt(0);             if (null == v) {                 return true;             } else {                 return child.getScrollY() >= v.getHeight() - child.getHeight();             }         }         if (child instanceof NestedScrollView) {             View v = ((NestedScrollView) child).getChildAt(0);             if (null == v) {                 return true;             } else {                 return child.getScrollY() >= v.getHeight() - child.getHeight();             }         }         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 (child.getScrollY() == 0);         }         return false;     }       /**      * 通过addView实现效果回弹效果      *      * @param replaceChildView 需要替换的View      */     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) {         this.onBounceStateListener = onBounceStateListener;     }       @Override     public boolean dispatchKeyEvent(KeyEvent event) {         try {             return super.dispatchKeyEvent(event);         } catch (IllegalArgumentException | IllegalStateException e) {             e.printStackTrace();         }         return false;     }       @Override     public void dispatchWindowFocusChanged(boolean hasFocus) {         try {             super.dispatchWindowFocusChanged(hasFocus);         } catch (IllegalArgumentException | IllegalStateException e) {             e.printStackTrace();         }     }     }

二、注意要点

滑动结束的时候要防止动画抖动

private void handlePointerUp(MotionEvent event, int type) {         int pointerIndexLeave = event.getActionIndex();         int pointerIdLeave = event.getPointerId(pointerIndexLeave);         if (mPointerId == pointerIdLeave) {             int reIndex = pointerIndexLeave == 0 ? 1 : 0;             mPointerId = event.getPointerId(reIndex);             // 调整触摸位置,防止出现跳动             downY = event.getY(reIndex);         }     }

到此,关于“Android怎么自定义View实现竖向滑动回弹效果”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI