《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
生活随笔
收集整理的這篇文章主要介紹了
《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在《Android開發(fā)藝術(shù)探索》一書中自定義View一節(jié)中提到了關(guān)于一個(gè)類似橫向滑動(dòng)List的自定義ViewGroup:HorizontalScrollViewEx。如果你使用過(guò)的話就會(huì)發(fā)現(xiàn),使用起來(lái)十分別扭。下面就是其原代碼:
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;// 分別記錄上次滑動(dòng)的坐標(biāo)private int mLastX = 0;private int mLastY = 0;// 分別記錄上次滑動(dòng)的坐標(biāo)(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();} }而利用書中提到的使用動(dòng)畫來(lái)實(shí)現(xiàn)平滑滑動(dòng)的話,體驗(yàn)會(huì)好很多,下面是我改進(jìn)的代碼,主要修改了:smoothScrollBy(int dx, int dy)這個(gè)函數(shù),讀者可自行比較,以做學(xué)習(xí)參考:
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;// 分別記錄上次滑動(dòng)的坐標(biāo)private int mLastX = 0;private int mLastY = 0;// 分別記錄上次滑動(dòng)的坐標(biāo)(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) {//根據(jù)速度來(lái)決定要移動(dòng)多少個(gè)Child,這里是500,可以調(diào)整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();} }總結(jié)
以上是生活随笔為你收集整理的《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网页中获取微信用户是否关注订阅号的思路
- 下一篇: Appium 移动端自动化 - Andr