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(); //First measure the width and height of all child views 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) {//If the width is wrap_content, width goes to the width of the first subview * number of subviews width = getChildAt(0).getWidth() * mChildSize; } if (heightMode == MeasureSpec.AT_MOST) {//If the height is wrap_content, height will take the height of the first child 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; / / Loop layout of the position of each child view for (int i = 0; i < mChildSize; i++) { View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { mChildWidth = childView.getMeasuredWidth(); //The sub-views are arranged in horizontal order, without considering their own padding value and the margin value of the sub-view 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(); } }
The activity_main.xml in MainActivity can be written like this:
<?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>
Reference: android development art exploration