publicclassHorizontalViewextendsViewGroup{ //... 省略构造方法代码和onMeasure的代码 @Override protectedvoidonLayout(boolean changed, int l, int t, int r, int b){ int childCount = getChildCount(); int left = 0; View child; for (int i = 0; i < childCount; i++) { child = getChildAt(i); if (child.getVisibility() != View.GONE) { int width = child.getMeasuredWidth(); childWidth = width; child.layout(left, 0, left + width, child.getMeasuredHeight()); left += width; } } }
publicvoidinit(){ scroller = new Scroller(getContext()); tracker = VelocityTracker.obtain(); }
//todo intercept的拦截逻辑 @Override publicbooleanonInterceptTouchEvent(MotionEvent event){ boolean intercept = false; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: intercept = false; //如果动画还没有执行完成,则打断 if (!scroller.isFinished()) { scroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: int deltaX = x - lastInterceptX; int deltaY = y - lastInterceptY; //水平方向距离长 MOVE中返回true一次,后续的MOVE和UP都不会收到此请求 if (Math.abs(deltaX) - Math.abs(deltaY) > 0) { intercept = true; Log.i("wangshu","intercept = true"); } else { intercept = false; Log.i("wangshu","intercept = false"); } break; case MotionEvent.ACTION_UP: intercept = false; break; } //因为DOWN返回false,所以onTouchEvent中无法获取DOWN事件,这里要负责设置lastX,lastY lastX = x; lastY = y; lastInterceptX = x; lastInterceptY = y; return intercept; }
@Override publicbooleanonTouchEvent(MotionEvent event){ tracker.addMovement(event); int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (!scroller.isFinished()) { scroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: //跟随手指滑动 int deltaX = x - lastX; scrollBy(-deltaX, 0); break; //释放手指以后开始自动滑动到目标位置 case MotionEvent.ACTION_UP: //相对于当前View滑动的距离,正为向左,负为向右 int distance = getScrollX() - currentIndex * childWidth;
//必须滑动的距离要大于1/2个宽度,否则不会切换到其他页面 if (Math.abs(distance) > childWidth / 2) { if (distance > 0) { currentIndex++; } else { currentIndex--; } } else { tracker.computeCurrentVelocity(1000); float xV = tracker.getXVelocity(); if (Math.abs(xV) > 50) { if (xV > 0) { currentIndex--; } else { currentIndex++; } } } currentIndex = currentIndex < 0 ? 0 : currentIndex > getChildCount() - 1 ? getChildCount() - 1 : currentIndex; smoothScrollTo(currentIndex * childWidth, 0); tracker.clear(); break; default: break; } lastX = x; lastY = y; returntrue; } @Override protectedvoidonMeasure(int widthMeasureSpec, int heightMeasureSpec){ super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //测量所有子元素 measureChildren(widthMeasureSpec, heightMeasureSpec); //处理wrap_content的情况 if (getChildCount() == 0) { setMeasuredDimension(0, 0); } elseif (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) { View childOne = getChildAt(0); int childWidth = childOne.getMeasuredWidth(); int childHeight = childOne.getMeasuredHeight(); setMeasuredDimension(childWidth * getChildCount(), childHeight); } elseif (widthMode == MeasureSpec.AT_MOST) { View childOne = getChildAt(0); int childWidth = childOne.getMeasuredWidth(); setMeasuredDimension(childWidth * getChildCount(), heightSize); } elseif (heightMode == MeasureSpec.AT_MOST) { int childHeight = getChildAt(0).getMeasuredHeight(); setMeasuredDimension(widthSize, childHeight); } } @Override publicvoidcomputeScroll(){ super.computeScroll(); if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } } publicvoidsmoothScrollTo(int destX, int destY){ scroller.startScroll(getScrollX(), getScrollY(), destX - getScrollX(), destY - getScrollY(), 1000); invalidate(); } @Override protectedvoidonLayout(boolean changed, int l, int t, int r, int b){ int childCount = getChildCount(); int left = 0; //左边的距离 View child; //遍历布局子元素 for (int i = 0; i < childCount; i++) { child = getChildAt(i); if (child.getVisibility() != View.GONE) { int width = child.getMeasuredWidth(); childWidth = width; //赋值给子元素宽度变量 child.layout(left, 0, left + width, child.getMeasuredHeight()); left += width; } } } }