實現彈性滑動的共同的思想:將一次大滑動分成若干次小的滑動並在一個時間段內完成。
彈性滑動方式: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>
複製程式碼