欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android自定义弹性滑动View

程序员文章站 2024-03-24 17:45:34
...

1.记录一下自己自定义View

2.直接子View只能是一个

public class SlideView extends ViewGroup {
    private static final String TAG = "ScrollLinearLayout";
    private int lastY;//记录上一个位置
    private Scroller mScroller;//回弹的动画效果
    private View mChildView;

    public SlideView(Context context) {
        this(context, null);
    }

    public SlideView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public SlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        mScroller = new Scroller(context);
        setClickable(true);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        int childCount = getChildCount();
        if (childCount > 1) {
            throw new RuntimeException("只能有一个子View");
        }
        mChildView = getChildAt(0);
        if (mChildView == null) {
            throw new RuntimeException("没有子View");
        }

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        Log.e(TAG, "onTouchEvent: y==" + y);
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:

                int mScrollY = lastY - y;//手指滑动的距离
                Log.e(TAG, "dispatchTouchEvent: mScrollY==" + mScrollY + " getScrollY()==" + getScrollY());

                /**
                 * 子View在中间,触摸事件交给子View
                 */
                if (!canPullDown() && !canPullUp()) {
                    lastY = y;
                    if (getScrollY() != 0) {//子View到了中间位置,父View还有移动的距离,父View恢复原位
                        int scrollY = getScrollY();
                        mScroller.startScroll(0, scrollY, 0, -scrollY, 0);
                        invalidate();
                    }
                    break;
                }

                if (canPullDown() && mScrollY < 0) {//顶部往下拉
                    mScrollY = (int) (mScrollY * scan());
                } else if (canPullUp() && mScrollY > 0) {//底部往上拉
                    mScrollY = (int) (mScrollY * scan());
                } else {
                    if (Math.abs(mScrollY) > Math.abs(getScrollY())) {//边界问题,移动的距离大于当前的滑动的距离
                        mScrollY = -getScrollY();
                    }
                }
                scrollBy(0, mScrollY);//滑动
                if (getScrollY() == 0) {
                    break;
                }

                lastY = y;
                return true;//事件自己消费
            case MotionEvent.ACTION_UP:
                int scrollY = getScrollY();
                mScroller.startScroll(0, scrollY, 0, -scrollY);
                invalidate();
                break;
        }
        lastY = y;
        return super.dispatchTouchEvent(event);
    }

    /**
     * 滑动的速度
     *
     * @return
     */
    private float scan() {
        return 0.5f;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //不能用这个来测量子View的大小,不准确
//        measureChildren(widthMeasureSpec, heightMeasureSpec);

        measureChildWithMargins(getChildAt(0), widthMeasureSpec, 0, heightMeasureSpec, 0);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(getChildTotalWidth(), getChildTotalHeight());
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(getChildTotalWidth(), heightSize);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSize, getChildTotalHeight());
        } else {
            setMeasuredDimension(widthSize, heightSize);
        }
    }

    /**
     * 得到子View的宽度
     *
     * @return
     */
    private int getChildTotalWidth() {
        int childCount = getChildCount();
        int width = 0;
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i);
            MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
            width += childAt.getMeasuredWidth() + layoutParams.leftMargin;
        }
        return width;
    }

    /**
     * 得到子View的高度
     *
     * @return
     */
    private int getChildTotalHeight() {
        int childCount = getChildCount();
        int height = 0;
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i);
            MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
            height += childAt.getMeasuredHeight() + layoutParams.topMargin;
        }
        return height;
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        Log.e(TAG, "onLayout: r==" + r + " b==" + b + " l==" + l + " t==" + t);
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i);
            MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();

            int left = layoutParams.leftMargin + getPaddingLeft();
            int top = layoutParams.topMargin + getPaddingTop();
            int right = left + childAt.getMeasuredWidth();
            int bottom = top + childAt.getMeasuredHeight();

            childAt.layout(left, top, right, bottom);
        }
    }

    //到底顶部,可以下拉
    private boolean canPullDown() {
        if (mChildView instanceof ScrollView) {
            ScrollView scrollView = (ScrollView) mChildView;
            if (scrollView.getScrollY() == 0) {
                return true;
            }
        } else if (mChildView instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) mChildView;
            if (!recyclerView.canScrollVertically(-1)) {
                return true;
            }
        } else if (mChildView instanceof ListView) {
            ListView listView = (ListView) mChildView;
            if (!listView.canScrollVertically(-1)) {
                return true;
            }
        } else {
            return true;
        }
        return false;
    }

    //到达底部,可以上拉
    private boolean canPullUp() {
        if (mChildView instanceof ScrollView) {
            ScrollView scrollView = (ScrollView) mChildView;
            boolean b = scrollView.canScrollVertically(1);
            if (!b) {
                return true;
            }
        } else if (mChildView instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) mChildView;
            boolean b = recyclerView.canScrollVertically(1);
            if (!b) {
                return true;
            }
        } else if (mChildView instanceof ListView) {
            ListView listView = (ListView) mChildView;
            boolean b = listView.canScrollVertically(1);
            if (!b) {
                return true;
            }
        } else {
            return true;
        }
        return false;
    }

    @Override
    public void computeScroll() {
        // 重写computeScroll()方法,完成回弹
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }
}

3.使用

    <com.example.testretrofitrxjava.widget.SlideView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_test"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </com.example.testretrofitrxjava.widget.SlideView>


上一篇: Java底层原理篇

下一篇: gulp使用