【android】View的事件体系3-弹性滑动
2017-05-23 22:21
399 查看
3弹性滑动
1使用Scroller
2通过动画
3使用延时策略
上面是 Scroller 典型的使用方法,它的工作原理是:当我们构造一个 Scroller 对象并且调用它的
startX 和 startY 表示的是滑动的起点。
dx 和 dy 表示的是滑动的距离。
duration 表示的是滑动时间。
到此为止,都没有看到 Scroller 是如何实现弹性滑动的,其实是在
再看一下
这个方法会根据时间流逝来计算当前的 scrollX 和 scrollY 的值。如果这个方法返回 true,表示动画过程至今还没有完成。
概括 Scroller 的工作原理: Scroller 本身并不能完成 View 的滑动,需要配合 View 的一个计算方法才能完成弹性滑动的效果,它不断让 View 重绘,每一次重绘距离滑动开始时间有一个时间间隔,通过这个时间间隔得出 View 当前的滑动位置,然后就通过 scrollTo 可劲滑。每次重绘都滑动一点,摩擦摩擦在光滑的地面上…仿佛在滑动,就成弹性滑动了。
但是我们可以用动画的特性来实现一些动画不能实现效果,比如我们通过 Scroller 来实现 View 的弹性滑动:
上述代码中,动画只是在 1000ms 内完成了。利用这个特性,我们就可以在动画的每一帧到来时获取动画完成的比例,然后再根据这个比例计算出当前 View 所要滑动的距离,然后通过
Handler示例:
上面代码是在大约1000ms内将 View 的内容向左移动 100px。之所以是大约,是因为采用这种方式无法精确地定时,原因是系统的消息调度也是需要时间的,并且所需的时间不定。
1使用Scroller
2通过动画
3使用延时策略
3、弹性滑动
View 的滑动如果过于生硬的话,用户体验会很差劲,所以需要实现渐进式滑动。这种滑动的基本思想是将一次大的滑动拆分成若干次小的滑动。以下是几种实现方法。3.1、使用Scroller
这个在View的事件体系1里面有,现在看它为什么能够实现view的弹性滑动。Scroller scroller = new Scroller(mContext); //缓慢滚动到指定位置 private void smoothScrollTo(int destX, int destY){ int scrollX = getScroller(); int deltaX = destX - scrollX; //1000ms内滑向destX,效果就是慢慢滑动 mScroller.startScroll(scrollX, 0, deltaX, 0, 1000); invalidate(); } @override public void computeScroll(){ if (mScroller.computeScrollOffset()){ scrollTo(mScrollrt.getCurrX(),mScroller.getCurrY()); postInvalidate(); } }
上面是 Scroller 典型的使用方法,它的工作原理是:当我们构造一个 Scroller 对象并且调用它的
startScroll方法时,Scroller 内部其实什么也没做,它只是保存了我们传递的几个参数,这几个参数从
startScroll的原型上就可以看出来,如下所示。
public void startScroll(int startX, int startY, int dx, int dy, int duration) { mMode = SCROLL_MODE; mFinished = false; mDuration = duration; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY; mFinalX = startX + dx; mFinalY = startY + dy; mDeltaX = dx; mDeltaY = dy; mDurationReciprocal = 1.0f / (float) mDuration; }
startX 和 startY 表示的是滑动的起点。
dx 和 dy 表示的是滑动的距离。
duration 表示的是滑动时间。
到此为止,都没有看到 Scroller 是如何实现弹性滑动的,其实是在
startScroll()方法下面的
invalidat 4000 e()方法。
invalidate()方法会导致 View 重绘,在 View 的
draw()方法中又会去调用
computeScroll()方法,
computeScroll()方法在 View 中是一个空实现,因此需要我们自己去实现,上面的代码已经实现了这个方法。正是因为这个方法 View 才能实现弹性滑动。
再看一下
computeScroll()方法中写的 Scroller 的
computeScrollOffset()方法的实现,如下:
/** * Call this when you want to know the new location. If it returns true, * the animation is not yet finished. */ public boolean computeScrollOffset() { ... int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); if (timePassed < mDuration) {//过去的时间 < 动画规定总时长 switch (mMode) { case SCROLL_MODE: final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; ... } } return true; }
这个方法会根据时间流逝来计算当前的 scrollX 和 scrollY 的值。如果这个方法返回 true,表示动画过程至今还没有完成。
概括 Scroller 的工作原理: Scroller 本身并不能完成 View 的滑动,需要配合 View 的一个计算方法才能完成弹性滑动的效果,它不断让 View 重绘,每一次重绘距离滑动开始时间有一个时间间隔,通过这个时间间隔得出 View 当前的滑动位置,然后就通过 scrollTo 可劲滑。每次重绘都滑动一点,摩擦摩擦在光滑的地面上…仿佛在滑动,就成弹性滑动了。
3.2、通过动画
之前写过,动画本身就是一种渐进的过程,因此通过它来实现的滑动天然就具有弹性滑动的效果。但是我们可以用动画的特性来实现一些动画不能实现效果,比如我们通过 Scroller 来实现 View 的弹性滑动:
final int startX = 0; final int deltaX = 100; ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000); animator.addUpdateListener(new AnimatorUpdateListener(){ @override public void onAnimationUpdate(ValueAnimator animator){ float fraction = animator.getAnimatedFraction(); btn.scrollTo(startX + (int)(deltaX * fraction), 0); } }); animator.start();
上述代码中,动画只是在 1000ms 内完成了。利用这个特性,我们就可以在动画的每一帧到来时获取动画完成的比例,然后再根据这个比例计算出当前 View 所要滑动的距离,然后通过
scrollTo()滑动。除此之外,我们完全可以在
onAnimationUpdate()方法中加上想要的任何操作。
3.3、使用延时策略
延时策略的核心思想是:通过发送一系列延时消息从而达到一种渐进式的效果,具体来说可以使用 Handler 或 View 的postDelayed()方法,也可以使用线程的
sleep()方法。
Handler示例:
private static final int MESSAGE_SCROLL_TO = 1; private static final int FRAME_COUNT = 30; private static final int DELAYED_TIME = 33; private int mCount = 0; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler(){ public void handleMessage(Message msg){ switch(msg.what){ case MESSAGE_SCROLL_TO:{ mCount++; if(mCount <= FRAME_COUNT){ float fraction = mCount / (float)FRAME_COUNT; int scrollX = (int)(fraction * 100); btn.scrollTo(scrollX, 0); mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO, DELAYED_TIME); } break; } default: break; } } };
上面代码是在大约1000ms内将 View 的内容向左移动 100px。之所以是大约,是因为采用这种方式无法精确地定时,原因是系统的消息调度也是需要时间的,并且所需的时间不定。
相关文章推荐
- Android读书笔记-------View事件体系(2)滑动及弹性滑动
- View的事件体系---V3.3 弹性滑动
- Android——View的事件体系(三)View的滑动冲突
- View的事件体系之二 View的滑动以及弹性滑动
- View的事件体系(上)(View基础知识,滑动,弹性滑动)
- 《View的事件体系》(三)弹性滑动
- 【android】View的事件体系2-滑动方式
- View的事件体系之--View的弹性滑动Scroller
- Android——View的事件体系(一)View的滑动
- Android中View的事件体系(2)——View滑动与事件分发
- 学习笔记:View的事件体系3:弹性滑动
- android ViewPager滑动事件
- Android技术之View的事件分发机制和滑动冲突解决方案
- Android使用Handler实现View弹性滑动
- 【读书笔记】【Android 开发艺术探索】第3章 View 的事件体系
- android开发之定制ViewPager滑动事件
- 《Android 开发艺术探索》笔记——(3)View 的事件体系
- Android——View的事件体系(二)View的事件分发机制
- 【Android】ViewPager实现图片左右滑动播放及添加点击事件
- Android 笔记 ViewPager的滑动与子view内部滑动事件的冲突问题