《Android藝術開發探索》學習筆記之View的事件體系(View的彈性滑動)

鋸齒流沙發表於2017-12-26

實現彈性滑動的共同的思想:將一次大滑動分成若干次小的滑動並在一個時間段內完成。

彈性滑動方式:Scroller、動畫、延時策略。

Scroller

View

以上就是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>

複製程式碼

相關文章