根据源码仿写HorizontalScrollView
package com.myf.scrollerscalerulerview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
/**
* 仿写
* @author ZH-SW-Mengyf
*
*/
public class HScrollerLayout extends ViewGroup {
/**
* 判定为拖动的最小移动像素数
*/
private int mTouchSlop;
/**
* 界面可滚动的左边界
*/
private int mLeftBorder;
/**
* 界面可滚动的右边界
*/
private int mRightBorder;
private int mEventX;
private int mOverscrollDistance;
private int mLastMotionX;
private boolean mIsBeingDragged= false;
private int mScrollX;
public HScrollerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public HScrollerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public HScrollerLayout(Context context) {
super(context);
init(context);
}
private void init(Context context) {
// 第一步,创建Scroller的实例
ViewConfiguration configuration = ViewConfiguration.get(context);
// 获取TouchSlop值
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
mOverscrollDistance = configuration.getScaledOverscrollDistance();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
// 为ScrollerLayout中的每一个子控件测量大小
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
// 为ScrollerLayout中的每一个子控件在水平方向上进行布局
childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1)* childView.getMeasuredWidth(),childView.getMeasuredHeight());
}
// 初始化左右边界值
mLeftBorder = getChildAt(0).getLeft();
mRightBorder = getChildAt(getChildCount() - 1).getRight();
final int scrollRange = Math.max(0, getWidth() - (mRightBorder - mLeftBorder));
mScrollX = scrollRange;
if (mScrollX > scrollRange) {
mScrollX = scrollRange;
}
else if (mScrollX < 0) {
mScrollX = 0;
}
scrollTo(mScrollX, 0);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mEventX = (int) ev.getX();
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
int xDiff = (int) Math.abs(mLastMotionX - mEventX);
// 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
if (xDiff > mTouchSlop) {
mIsBeingDragged = true;
mLastMotionX = mEventX;
return true;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mIsBeingDragged = false;
break;
}
return super.onInterceptTouchEvent(ev);
}
@SuppressLint("NewApi") @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
int x = (int) event.getX();
int deltaX = (int) (mLastMotionX - x);
if (!mIsBeingDragged) {
mIsBeingDragged = true;
if (deltaX > 0) {
deltaX -= mTouchSlop;
} else {
deltaX += mTouchSlop;
}
}
if (mIsBeingDragged) {
mLastMotionX = x;
final int range = getScrollRange();
Log.d("myf", "range" + range + "====" + mOverscrollDistance);
overScrollBy(deltaX, 0, mScrollX, 0, range, 0, mOverscrollDistance, 0, true);
postInvalidateOnAnimation();
}
break;
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
mIsBeingDragged = false;
}
break;
}
return true;
}
/**
* 可以滚动的最大范围
* @return
*/
private int getScrollRange() {
int scrollRange = (mRightBorder - mLeftBorder) - getWidth();
return scrollRange;
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,boolean clampedY) {
mScrollX = scrollX;
Log.d("myf", "onOverScrolled scrollX:"+scrollX);
super.scrollTo(scrollX, scrollY);
}
}