弹性滑动,就是将一个大的滑动分成若干个小的滑动,并在一个事件段内,完成。实现方式有多种:
1.使用Scroller
对于Scroller 在View的基础知识中有过一点介绍,看一下源码,是如何实现弹性滑动的
Scroller scroller = new Scroller(mContext);
//缓慢的移动到指定位置
private void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int deltaX = destX - sCrollX;
//1000ms滑向destX,效果就是慢慢移动
mScroller.startScroll(scrollX,0,deltaX,0,1000);
invalidate();
}
上面是一个典型的实现方式,先构造一个Scroller对象,并且调用startScroll方法时,Scroller内部没做什么,只保存了我们传递的参数,这几个参数可以看一下startScroll()方法,如下:
/**
*
* @param startX 起始位置x
* @param startY 起始位置Y
* @param dx x滑动距离
* @param dy y滑动距离
* @param duration 滑动时间
*/
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;
mDetalX = dx;
mDetalY = dy;
mDurationReciprocal = 1.0f/(float)mDuration;
}
注意这个滑动的是View的内容,并非View本身,startScroll方法并没有做View的滑动,那为什么View会滑动了?其实主要是invalidate会导致View重绘,而在View的draw方法中,又会调用computeScroll,但此方法在view中是空实现,需要我们自己实现,如下代码:
@override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScrollder.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
正因为这个computScroll()方法,view才会弹性滑动。实现过程View重绘,会在draw方法中调用computeScroll,而computeScroll又会去像Scroller获取当前的scrollX和scrollY的值,然后再调用scrollTo对View移动,接着又会调用postInvalidate方法进行第二次重绘View,这次和第一次一样,如此反复,直到整个滑动过程结束。
再看一下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,表示还没滑动完,false,表示滑动结束。
2、通过动画
动画本身是一个渐近的过程,所以它实现的滑动也是具有弹性效果,比如将一个View的内容在100ms内向左移动100像素
ObjectAnimation .ofFloat(targetView,"translationX",0,100).setDuration(100).start();
使用动画的特性来实现一些动画不能实现的效果,用ScrollTo实现弹性滑动:
final int startX = 0;
final int deltaX = 100;
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000);
animation.addUpdateListener(new Animator animator(){
@override
public void onAnimationUpdate(ValueAnimator animator){
float fraction = animator.getAnimateFraction();
mButton1.scrollTo(startX,+(int)(deltaX+fraction),0);
}
)};
animator.start();
发现这个实现过程和Scroller的实现过程类似,也是在一个时间段,通过一个百分比配合scrollerTo方法,实现弹性滑动效果。采取这种方式,也可以在哦你AnimationUpdate方法中做一些其它我们想要的操作和动画效果。
3、使用演示策略
延时策略就是通过发送一系列延时消息达到一种渐进的效果,可使用Handler或者View的postDelayed,或者sleep方法。下面已Handler为例,将View的内容想做移动100像素:
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 hangleMessage(Message msg){
switch(msg.what){
case:MESSAGE_SCROLL_TO:
mCount++;
if(mCount <+ FRAME_COUNT){
float fraction = mcount / (float) FRAME_COUNT;
int scrllX = (int)(fraction * 100);
mButton1.scrollTo(scrolX, 0);
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELSYED_TIME);
}
break;
}
default:
break;
}
};
};
特别声明:内容总结来源《Android开发艺术探索》,仅记录学习,如有侵权或不对之处,还请告知,定当删除或改正