《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
生活随笔
收集整理的这篇文章主要介绍了
《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
在《Android开发艺术探索》一书中自定义View一节中提到了关于一个类似横向滑动List的自定义ViewGroup:HorizontalScrollViewEx。如果你使用过的话就会发现,使用起来十分别扭。下面就是其原代码:
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.ViewGroup; import android.widget.Scroller;public class HorizontalScrollViewEx extends ViewGroup {private static final String TAG = "HorizontalScrollViewEx";private int mChildrenSize;private int mChildWidth;private int mChildIndex;// 分别记录上次滑动的坐标private int mLastX = 0;private int mLastY = 0;// 分别记录上次滑动的坐标(onInterceptTouchEvent)private int mLastXIntercept = 0;private int mLastYIntercept = 0;private Scroller mScroller;private VelocityTracker mVelocityTracker;public HorizontalScrollViewEx(Context context) {super(context);init();}public HorizontalScrollViewEx(Context context, AttributeSet attrs) {super(context, attrs);init();}public HorizontalScrollViewEx(Context context, AttributeSet attrs,int defStyle) {super(context, attrs, defStyle);init();}private void init() {mScroller = new Scroller(getContext());mVelocityTracker = VelocityTracker.obtain();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {boolean intercepted = false;int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {intercepted = false;if (!mScroller.isFinished()) {mScroller.abortAnimation();intercepted = true;}break;}case MotionEvent.ACTION_MOVE: {int deltaX = x - mLastXIntercept;int deltaY = y - mLastYIntercept;if (Math.abs(deltaX) > Math.abs(deltaY)) {intercepted = true;} else {intercepted = false;}break;}case MotionEvent.ACTION_UP: {intercepted = false;break;}default:break;}Log.d(TAG, "intercepted=" + intercepted);mLastX = x;mLastY = y;mLastXIntercept = x;mLastYIntercept = y;return intercepted;}@Overridepublic 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 deltaX = x - mLastX;int deltaY = y - mLastY;scrollBy(-deltaX, 0);break;}case MotionEvent.ACTION_UP: {int scrollX = getScrollX();int scrollToChildIndex = scrollX / mChildWidth;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, mChildrenSize - 1));int dx = mChildIndex * mChildWidth - scrollX;smoothScrollBy(dx, 0);mVelocityTracker.clear();break;}default:break;}mLastX = x;mLastY = y;return true;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int measuredWidth = 0;int measuredHeight = 0;final int childCount = getChildCount();measureChildren(widthMeasureSpec, heightMeasureSpec);int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);if (childCount == 0) {setMeasuredDimension(0, 0);} else if (heightSpecMode == MeasureSpec.AT_MOST) {final View childView = getChildAt(0);measuredHeight = childView.getMeasuredHeight();setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight());} else if (widthSpecMode == MeasureSpec.AT_MOST) {final View childView = getChildAt(0);measuredWidth = childView.getMeasuredWidth() * childCount;setMeasuredDimension(measuredWidth, heightSpaceSize);} else {final View childView = getChildAt(0);measuredWidth = childView.getMeasuredWidth() * childCount;measuredHeight = childView.getMeasuredHeight();setMeasuredDimension(measuredWidth, measuredHeight);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int childLeft = 0;final int childCount = getChildCount();mChildrenSize = childCount;for (int i = 0; i < childCount; i++) {final View childView = getChildAt(i);if (childView.getVisibility() != View.GONE) {final int childWidth = childView.getMeasuredWidth();mChildWidth = childWidth;childView.layout(childLeft, 0, childLeft + childWidth,childView.getMeasuredHeight());childLeft += childWidth;}}}private void smoothScrollBy(int dx, int dy) {mScroller.startScroll(getScrollX(), 0, dx, 0, 500);invalidate();}@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}@Overrideprotected void onDetachedFromWindow() {mVelocityTracker.recycle();super.onDetachedFromWindow();} }而利用书中提到的使用动画来实现平滑滑动的话,体验会好很多,下面是我改进的代码,主要修改了:smoothScrollBy(int dx, int dy)这个函数,读者可自行比较,以做学习参考:
import android.animation.ValueAnimator; 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.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.Scroller;public class HorizontalScrollViewEx extends ViewGroup {private static final String TAG = "HorizontalScrollViewEx";private int mChildrenSize;private int mChildWidth;private int mChildIndex;// 分别记录上次滑动的坐标private int mLastX = 0;private int mLastY = 0;// 分别记录上次滑动的坐标(onInterceptTouchEvent)private int mLastXIntercept = 0;private int mLastYIntercept = 0;private Scroller mScroller;private VelocityTracker mVelocityTracker;ValueAnimator animator;public HorizontalScrollViewEx(Context context) {super(context);init();}public HorizontalScrollViewEx(Context context, AttributeSet attrs) {super(context, attrs);init();}public HorizontalScrollViewEx(Context context, AttributeSet attrs,int defStyle) {super(context, attrs, defStyle);init();}private void init() {mScroller = new Scroller(getContext());mVelocityTracker = VelocityTracker.obtain();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {boolean intercepted = false;int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {intercepted = false;if (!mScroller.isFinished()) {mScroller.abortAnimation();intercepted = true;}break;}case MotionEvent.ACTION_MOVE: {int deltaX = x - mLastXIntercept;int deltaY = y - mLastYIntercept;if (Math.abs(deltaX) > Math.abs(deltaY)) {intercepted = true;} else {intercepted = false;}break;}case MotionEvent.ACTION_UP: {intercepted = false;break;}default:break;}Log.d(TAG, "intercepted=" + intercepted);mLastX = x;mLastY = y;mLastXIntercept = x;mLastYIntercept = y;return intercepted;}@Overridepublic 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(animator != null){if(animator.isRunning()){animator.cancel();}}break;}case MotionEvent.ACTION_MOVE: {int deltaX = x - mLastX;int deltaY = y - mLastY;scrollBy(-deltaX, 0);break;}case MotionEvent.ACTION_UP: {int scrollX = getScrollX();int scrollToChildIndex = scrollX / mChildWidth;mVelocityTracker.computeCurrentVelocity(1000);float xVelocity = mVelocityTracker.getXVelocity();if (Math.abs(xVelocity) >= 50) {//根据速度来决定要移动多少个Child,这里是500,可以调整mChildIndex = mChildIndex - (int)xVelocity/500;} else {mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;}mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));int dx = mChildIndex * mChildWidth - scrollX;smoothScrollBy(dx, 0);mVelocityTracker.clear();break;}default:break;}mLastX = x;mLastY = y;return true;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int measuredWidth = 0;int measuredHeight = 0;final int childCount = getChildCount();measureChildren(widthMeasureSpec, heightMeasureSpec);int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);if (childCount == 0) {setMeasuredDimension(0, 0);} else if (heightSpecMode == MeasureSpec.AT_MOST) {final View childView = getChildAt(0);measuredHeight = childView.getMeasuredHeight();setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight());} else if (widthSpecMode == MeasureSpec.AT_MOST) {final View childView = getChildAt(0);measuredWidth = childView.getMeasuredWidth() * childCount;setMeasuredDimension(measuredWidth, heightSpaceSize);} else {final View childView = getChildAt(0);measuredWidth = childView.getMeasuredWidth() * childCount;measuredHeight = childView.getMeasuredHeight();setMeasuredDimension(measuredWidth, measuredHeight);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int childLeft = 0;final int childCount = getChildCount();mChildrenSize = childCount;for (int i = 0; i < childCount; i++) {final View childView = getChildAt(i);if (childView.getVisibility() != View.GONE) {final int childWidth = childView.getMeasuredWidth();mChildWidth = childWidth;childView.layout(childLeft, 0, childLeft + childWidth,childView.getMeasuredHeight());childLeft += childWidth;}}}private void smoothScrollBy(int dx, int dy) {int startX = getScrollX();animator = ValueAnimator.ofInt(0, 1).setDuration(Math.abs(dx));animator.setInterpolator(new DecelerateInterpolator());animator.addUpdateListener(animation -> {float fraction = animation.getAnimatedFraction();scrollTo(startX + (int)(dx*fraction), 0);});animator.start();invalidate();}@Overrideprotected void onDetachedFromWindow() {mVelocityTracker.recycle();super.onDetachedFromWindow();} }总结
以上是生活随笔为你收集整理的《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 网页中获取微信用户是否关注订阅号的思路
- 下一篇: Appium 移动端自动化 - Andr