自定义View-HorizontalScrollView

package com.example.chenguang.androidarttest.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
 * Created by chenguang on 2018/2/12.
 */

public class HorizontalScrollView extends ViewGroup {

    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;
    private int mChildWidth;
    int mChildIndex;
    int mChildSize;

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

    public HorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    private void init() {
        mScroller = new Scroller(getContext());
        mVelocityTracker = VelocityTracker.obtain();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mChildSize = getChildCount();
        //先测量所有子view的宽高
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width = widthSize;
        int height = heightSize;
        if (widthMode == MeasureSpec.AT_MOST) {//如果宽为wrap_content,width就去第一个子view打的宽度*子view个数
            width = getChildAt(0).getWidth() * mChildSize;
        }
        if (heightMode == MeasureSpec.AT_MOST) {//如果高为wrap_content,height就取第一个子view的高度
            height = getChildAt(0).getMeasuredHeight();
        }
        setMeasuredDimension(width, height);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childLeft = 0;
        //循环布局每个子view的位置
        for (int i = 0; i < mChildSize; i++) {
            View childView = getChildAt(i);
            if (childView.getVisibility() != View.GONE) {
                mChildWidth = childView.getMeasuredWidth();
                //子view按水平方向顺序排列,没有考虑自身的padding值和子view的margin值
                childView.layout(childLeft, 0, childLeft + mChildWidth, childView
                        .getMeasuredHeight());
                childLeft += mChildWidth;
            }
        }

    }

    int mLastX;
    int mLastY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        mVelocityTracker.addMovement(event);
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - mLastX;
                int dy = y - mLastY;
                scrollBy(-dx, 0);
                break;
            case MotionEvent.ACTION_UP:
                int scrollX = getScrollX();
                mVelocityTracker.computeCurrentVelocity(1000);
                float xVelocity = mVelocityTracker.getXVelocity();
                if (Math.abs(xVelocity) > 50) {
                    mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
                } else {
                    mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
                }
                mChildIndex = Math.max(0, Math.min(mChildIndex, mChildSize - 1));
                dx = mChildWidth * mChildIndex - scrollX;
                smoothScrollBy(dx, 0);
                mVelocityTracker.clear();
                break;
        }


        mLastX = x;
        mLastY = y;
        return true;

    }

    private void smoothScrollBy(int dx, int dy) {
        mScroller.startScroll(getScrollX(), dy, dx, 0, 1000);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        mVelocityTracker.clear();
        super.onDetachedFromWindow();
    }
}

MainActivity里的activity_main.xml可以这样写:

<?xml version="1.0" encoding="utf-8"?>
<com.example.chenguang.androidarttest.widget.HorizontalScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ccc">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f00"
        android:gravity="center"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#0f0"
        android:gravity="center"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00f"
        android:gravity="center"/>

</com.example.chenguang.androidarttest.widget.HorizontalScrollView>

参考:android开发艺术探索

猜你喜欢

转载自my.oschina.net/5501/blog/1624532
今日推荐