文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-06-30 05:07

关注

这篇文章主要介绍“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;    }         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实现竖向滑动回弹效果”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯