package com.wise.extend; /** * 自定义首页滑动控件 */ import com.wise.extend.OnViewChangeListener; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.Scroller; public class HScrollLayout extends ViewGroup { private static final String TAG = "HScrollLayout"; private VelocityTracker velocityTracker;// 判断手势 private static final int SNAP_VELOCITY = 600; // 滑动速度 private int mCurScreen = 0; // 当前所在屏幕 private float downMotionX; // 按下x坐标 OnViewChangeListener mOnViewChangeListener; Scroller scroller; Context mContext; public HScrollLayout(Context context) { super(context); init(context); } public HScrollLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { scroller = new Scroller(context); mContext = context; mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } int desireWidth; int desireHeight; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); desireWidth = 0; desireHeight = 0; int count = getChildCount(); for (int i = 0; i < count; ++i) { View v = getChildAt(i); if (v.getVisibility() != View.GONE) { measureChild(v, widthMeasureSpec,heightMeasureSpec); desireWidth += v.getMeasuredWidth(); desireHeight = Math.max(desireHeight, v.getMeasuredHeight()); } } desireWidth += getPaddingLeft() + getPaddingRight(); desireHeight += getPaddingTop() + getPaddingBottom(); desireWidth = Math.max(desireWidth, getSuggestedMinimumWidth()); desireHeight = Math.max(desireHeight, getSuggestedMinimumHeight()); setMeasuredDimension(resolveSize(desireWidth, widthMeasureSpec), resolveSize(desireHeight, heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; final int count = getChildCount(); for (int i = 0; i < count; i++) { final View childView = getChildAt(i); final int width = childView.getMeasuredWidth(); childView.layout(childLeft, 0, childLeft + width, childView.getMeasuredHeight()); childLeft += width; } } private float mLastMotionX; private int mTouchSlop = 10; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //Log.d(TAG, "onInterceptTouchEvent = " + ev.getAction()); boolean xMoved = false; final float x = ev.getX(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastMotionX = x; downMotionX = ev.getX(); break; case MotionEvent.ACTION_MOVE: final int xDiff = (int) Math.abs(x - mLastMotionX); xMoved = xDiff > mTouchSlop; if ((mLastMotionX - x) <= 0 && getScrollX() <= 0){ }else{ //Log.d(TAG, "父控件停止感应"); getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: break; } // true滑动容器里感应不到点击事件,false,滑动容器里控件感应到点击事件 //return mTouchState != TOUCH_STATE_REST; //Log.d(TAG, "xMoved = " + xMoved); return xMoved; } @Override public boolean onTouchEvent(MotionEvent event) { //Log.d(TAG, "onTouchEvent = " + event.getAction()); float x = event.getX(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); if (!scroller.isFinished()) { // 解决在松开手滚动时,按下无效 scroller.abortAnimation(); } downMotionX = x; break; case MotionEvent.ACTION_MOVE: int deltaX = (int) (downMotionX - x); downMotionX = x; if (deltaX <= 0) {// 向右滑 if (getScrollX() <= 0) { //Log.d(TAG, "划不动"); } else { //Log.d(TAG, "不应该啊"); getParent().requestDisallowInterceptTouchEvent(true); scrollBy(deltaX, 0);// 画面跟随指尖 if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); } } else {// 像左滑 //Log.d(TAG, "父控件停止感应"); getParent().requestDisallowInterceptTouchEvent(true); scrollBy(deltaX, 0);// 画面跟随指尖 if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); } break; case MotionEvent.ACTION_UP: getParent().requestDisallowInterceptTouchEvent(false); int velocityX = 0; if (velocityTracker != null) { velocityTracker.addMovement(event); velocityTracker.computeCurrentVelocity(1000); velocityX = (int) velocityTracker.getXVelocity();// 计算x方向速度 velocityTracker.recycle(); velocityTracker = null; } if (velocityX > SNAP_VELOCITY && mCurScreen > 0) { // 速度快且不是第一屏 snapToScreen(mCurScreen - 1); } else if (velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1) {// 速度快且不是最后一屏 snapToScreen(mCurScreen + 1); } else { snapToDestination(); // 判断是否翻转 } break; case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); snapToDestination(); // 判断是否翻转 break; } return true; } /** * 跳转到那个屏幕 * * @param whichScreen */ public void snapToScreen(int whichScreen) { if (whichScreen > (getChildCount() - 1)) { addView(); } whichScreen = Math.max(0, Math.min(whichScreen, (getChildCount() - 1)));// 防止输入不再范围内的数字 if (getScrollX() != getWidth() * whichScreen) {// 时候需要移动 int delta = whichScreen * getWidth() - getScrollX(); // 还有多少没有显示 scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);// 滚动完剩下的距离 mCurScreen = whichScreen; invalidate(); if (mOnViewChangeListener != null) { mOnViewChangeListener.OnViewChange(whichScreen); } } } public void snapFastToScreen(int whichScreen){ whichScreen = Math.max(0, Math.min(whichScreen, (getChildCount() - 1)));// 防止输入不再范围内的数字 if (getScrollX() != getWidth() * whichScreen) {// 时候需要移动 int delta = whichScreen * getWidth() - getScrollX(); // 还有多少没有显示 scroller.startScroll(getScrollX(), 0, delta, 0);// 滚动完剩下的距离 mCurScreen = whichScreen; invalidate(); if (mOnViewChangeListener != null) { mOnViewChangeListener.OnViewChange(whichScreen); } } } /** * 滑动速度过慢的话调用这个方法判断是否滑动了半个屏幕,并计算出当前显示那个屏幕 */ private void snapToDestination() { int screenWidth = getWidth(); int destScreen = (getScrollX() + screenWidth / 2) / screenWidth; snapToScreen(destScreen); } @Override public void computeScroll() {// 需要,不然松手后不会滑动 if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } } public void setOnViewChangeListener( OnViewChangeListener onViewChangeListener) { mOnViewChangeListener = onViewChangeListener; } public void addView() { if (mOnViewChangeListener != null) { mOnViewChangeListener.OnLastView(); } } }