菜鸟进阶笔记|初探自定义View|05|自定义ViewGroup

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yang96515328/article/details/79975370

类似ScrollView的滑动,并附加黏性效果

自定义View中代码如下:

public class MyScrollView extends ViewGroup {
    private static final String TAG = "MyScrollView";
    private Scroller mScroller;
    private int mScreenHeight;    //获取屏幕高度
    int mLastY = 0;
    int mStart = 0;

    public MyScrollView(Context context) {
        super(context);
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        mScreenHeight = wm.getDefaultDisplay().getHeight(); //记录设备屏幕高度
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 在ViewGroup能够滚动之前,需要先放置好它的子View。使用遍历的方式来通知子View对自身进行测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount();
        for (int i = 0; i < count; ++i) {
            View childView = getChildAt(i);
            //要求其子View根据此View测量自己
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * 接下来就要对子View进行放置位置的设定。我们让每个子View都显示完整的一屏,方便后续操作。
     * 在放置子View前,需要确定整个ViewGroup的高度。
     * 在获取了整个ViewGroup的高度之后,就可以通过遍历来设定每个子View需要放置的位置了
     * 直接通过调用子View的Layout()方法,并将具体的位置座位参数传递进去即可,代码如下所示。
     * 在本例中由于让每个子View都占一屏的高度,因此整个ViewGroup的高度即子View的个数乘以屏幕的高度。
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        //设置ViewGroup的高度
        MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
        mlp.height = mScreenHeight * childCount;
        setLayoutParams(mlp);
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                child.layout(   //给子View设置位置
                        l,
                        i * mScreenHeight,
                        r,
                        (i + 1) * mScreenHeight
                );
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = y;
                mStart = getScrollY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (!mScroller.isFinished()) {  //确认滚动器是否完成滚动
                    mScroller.abortAnimation(); //停止动画
                }
                int dy = mLastY - y;
                if (getScrollY() < 0) {
                    dy = 0;
                }
                if (getScrollY() > mScreenHeight) {
                    dy = 0;
                }
                scrollBy(0, dy);
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                //当手指离开后,如果手指滑动超过一定距离,则平滑到下一个View,如果小于一定距离,则回滚到原来的位置。
                int mEnd = getScrollY();
                int dScrollY = mEnd - mStart;
                if (dScrollY > 0) {
                    if (dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
                    } else {
                        mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);
                    }
                } else {
                    if (-dScrollY < mScreenHeight / 3) {
                        mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
                    } else {
                        mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY);
                    }
                }
                break;
        }
        invalidate();
        return true;
    }

    //该回调在执行invalidate()方法时会执行
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {  //判断是否已终止滚动
            scrollTo(0, mScroller.getCurrY());
            postInvalidate();
        }
    }
}

在xml中如下使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.myview.myview.MyScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary" />
    </com.example.myview.myview.MyScrollView>
</LinearLayout>

就不贴效果图啦,跑一下就知道了(#^.^#)

阅读更多

没有更多推荐了,返回首页