实现弹性滑动的共同的思想:将一次大滑动分成若干次小的滑动并在一个时间段内完成。
弹性滑动方式:Scroller、动画、延时策略。
Scroller
以上就是Scroller的典型使用方法。
Sroller工作原理:当我们构造一个Scroller对象并且调用它的startScroll方法时,Scroller内部其实什么也没有做,它只是保存了我们传递的几个参数。仅仅调用startScroll是无法让View滑动的,因为它并没有做滑动相关的事情,接着就是调用invalidate方法,invalidate方法会导致View重绘,在View的draw方法中又会去调用computeScroll方法,computeScroll方法在View中是一个空实现,因此需要我们自己去实现,上图中的代码已经实现好了。
也就是说:当View重绘后会在draw方法中调用computeScroll,而computeScroll又会去向Scroller获取当前的ScrollX和ScrollY;然后通过ScrollTo方法实现滑动,接着又调用postInvalidate方法进行第二次重绘,这一次重绘的过程跟第一次重绘的过程一样,还是会导致computeScroll方法被调用,然后继续向Scroller获取当前的scrollX和ScrollY,并通过scrollTo方法滑动到新的位置,如此反复,直到整个过程结束。
概括:Scroller本身并不能实现View的滑动,它需要配合View的computeScroll方法才能完成弹性滑动的效果,它不断的让View重绘,而每一次重绘距滑动起始会有一个时间间隔,通过这个时间间隔Scroller就可以得出View当前的滑动位置,知道了滑动位置就可以通过ScrollTo方法完成View的滑动。就这样,View的每一次重绘都会导致View进行小幅度的滑动,而多次小幅度的滑动就组成了弹性滑动,这就是Scroller的工作机制。
通过动画
动画本身就是一种渐近的过程,通过它来实现的滑动天然就具有弹性效果。
ObjectAnimator.ofFloat(mTest,"translationX",0,100).setDuration(100).start();
复制代码
使用动画监听addUpdateListener实现一些动画不能实现的效果:
private int startX = 0;
private int deltaX = 100;
private void myAnimation() {
final ValueAnimator animator = ValueAnimator.ofInt(0, 1).setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float fraction = animator.getAnimatedFraction();
mTest.scrollTo(startX + (int) (deltaX * fraction), 0);
}
});
animator.start();
}
复制代码
以上就是在1s内完成整个动画效果,注意这里是滑动View的内容,并不是View本身。
使用延时策略
public class ViewScrollerActivity extends AppCompatActivity {
private Button mTest;
private static final int MESSAGE_SCROLL_TO = 0;
private static final int FRAME_COUNT = 30;
private static final int DELAYED_TIME = 33;
private int mCount = 0;
private Handler mHandler = new Handler(){
@Override
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);
mTest.scrollTo(scrollX,0);
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
}
break;
}
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_scroller);
mTest = (Button) this.findViewById(R.id.test);
mTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
}
});
}
}
复制代码
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context="com.main.scroll.ViewScrollerActivity">
<Button
android:id="@+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test"/>
</LinearLayout>
复制代码