1. 程式人生 > >Android ScrollView妙用(scrolling tricks詳解)

Android ScrollView妙用(scrolling tricks詳解)

最近辭職在家閒來無事搞起了Android studio,剛上手時各種頭痛,現在適應來一段時間發現它確實要比eclipse強大一些,那麼我們今天就來說一下scrollview的一些用法,相信很多人用scrollview時只是簡單的把它當一個滾動裝置來用,其實scrollview有很多簡單卻又炫酷的用法,先看個效果.


相信很多人會感到眼熟,這就是ScrollingTricks的效果,我們今天就是來分析它的工作原理,畢竟從原理上理解效果會更好。

1,STICKY

我們知道scrollview的onScrollChanged方法是隻能通過繼承scrollview來獲取的,那麼我們就通過介面的回撥把我們需要的值給取出來。

public class ObservableScrollView extends ScrollView {

    public Callbacks mCallbacks;

    public ObservableScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setCallbacks(Callbacks callbacks) {
        this.mCallbacks = callbacks;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mCallbacks != null){
            mCallbacks.onScrollchanged(t);
        }
    }

    /**
     * 由垂直方向滾動條代表的所有垂直範圍,預設的範圍是當前檢視的畫圖高度。
     */
    public int computeVerticalScrollRange(){
        return super.computeVerticalScrollRange();
    }

    public interface Callbacks {
        public void onScrollchanged(int t);

        public void onTouchUp();

        public void onTouchDown();
    }

}
接著我們可以在佈局中引用我們自己寫的scrollview
<com.example.apple.myapplication.ObservableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <View style="@style/Item.Top" />

            <View android:id="@+id/placeholder"
                android:layout_width="match_parent"
                android:layout_height="@dimen/sticky_height" />

            <View style="@style/Item.Bottom" />
            <View style="@style/Item.Bottom.Alt" />
            <View style="@style/Item.Bottom" />
            <View style="@style/Item.Bottom.Alt" />
            <View style="@style/Item.Bottom" />
            <View style="@style/Item.Bottom.Alt" />

        </LinearLayout>

        <TextView android:id="@+id/sticky" style="@style/Item.Sticky" />

    </FrameLayout>
</com.example.apple.myapplication.ObservableScrollView>

注意我們裡面一定要用FrameLayout
public class StickyActivity extends Activity implements ObservableScrollView.Callbacks {

    private TextView txtContent;
    private ObservableScrollView observableScrollView;
    private View mPlaceholderView;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky);
        mPlaceholderView = (View)findViewById(R.id.placeholder);
        txtContent = (TextView) findViewById(R.id.sticky);
        txtContent.setText("StickyActivity");
        observableScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
        observableScrollView.setCallbacks(this);
        /**
         * 當佈局繪製完全的時候我們才可以得到view.getTop()等
         */
        observableScrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                onScrollchanged(observableScrollView.getScrollY());

            }
        });
    }

    @Override
    public void onScrollchanged(int t) {
        int translation = Math.max(t,mPlaceholderView.getTop());
        txtContent.setTranslationY(translation);
    }

    @Override
    public void onTouchUp() {

    }

    @Override
    public void onTouchDown() {

    }
}

很簡單不是麼,不過在這裡還是要給大家解釋一下,getViewTreeObserver,因為我們要獲取到view.getTop的值,但我們在oncreate裡面獲取時獲取不到的,返回值永遠為0,所以我們要新增整體佈局監聽。

接下來的onScrollchanged方法我們上個圖解釋一下


為什麼我的眼裡充滿淚水,是因為我根本沒有繪畫天賦。。

這樣我們直觀的看一下,Math.max(t,gettop);就是不斷的比較,當t大於gettop的時候我們可以認為滑倒頂部了,接下來因為t還在增大我們setTranslationY也在不斷增大,所以效果上就是我們的textview停在了最上面。

2,QUICKRETURN


效果就是不管我們滑動了多遠只要向下滑動的時候我們的textview就可以顯示出來,我們接著分析程式碼,其實也不難

 /**
     * 上滑動狀態
     */
    private static final int STATE_ONSCREEN = 0;
    /**
     * 上滑動至完全遮蓋住mPlaceholderView
     */
    private static final int STATE_OFFSCREEN = 1;
    /**
     * 完全遮蓋住時,下滑狀態
     */
    private static final int STATE_RETURING = 2;
    private int mState = STATE_ONSCREEN;
    /**
     * 高度
     */
    private int mViewHeight;
    private int minRaw;

其他的基本類似,我們可以看到新增了三個狀態,以及一個minraw,這個值後面是用來做判斷以及確認位置的
   @Override
    public void onScrollchanged(int t) {
        int raw = mPlaceholderView.getTop() - t;
        int translationY = 0;
        switch (mState) {
            case STATE_ONSCREEN:
               // Log.d("TAG","STATE_ONSCREEN");
                if (raw < -mViewHeight) {
                    mState = STATE_OFFSCREEN;
                    minRaw = raw;
                }
                translationY = raw;
                break;
            case STATE_OFFSCREEN:
               // Log.d("TAG","STATE_OFFSCREEN");
                if (raw<=minRaw){
                    minRaw = raw;
                }
                else{
                     mState = STATE_RETURING;
                }
                translationY = raw;
                break;
            case STATE_RETURING:
                translationY = (raw - minRaw) - mViewHeight;
                Log.d("TAG","translationY:"+translationY);
                if (translationY > 0) {
                    translationY = 0;
                    minRaw = raw - mViewHeight;
                }

                if (raw > 0) {
                    mState = STATE_ONSCREEN;
                    translationY = raw;
                }

                if (translationY < -mViewHeight) {
                    mState = STATE_OFFSCREEN;
                    minRaw = raw;
                }
                break;
        }
        txtContent.setTranslationY(translationY+t);
    }

這次在onscrollchange裡面的程式碼可能多了一些,但是隻要理解了其實沒什麼。

首先是raw = getTop() - t;

空間能力強的可能已經自行腦補出來畫面了,我們這裡分析一下t是y軸上的變化值,gettop為距離頂部的值,那麼我們這樣一相減得到的是不是當前位置。

STATE_ONSCREEN:向上滑動當raw < -ViewHeight時說明螢幕上已經徹底看不到我們的text了,狀態就轉變成STATE_OFFSCREEN.

STATE_OFFSCREEN:此時我們已經看不到text所以我們只要向下滑動的時候minraw>raw = true;此時就轉變成STATE_RETURING.

STATE_RETURING:因為我們時向下滑動,所以我們要算出來滑動的距離以及text顯示的部分,所以translationY = (raw - minRaw) - mViewHeight;

這樣的話應該就沒什麼難理解的了,最後說下android studio真實讓人冰火倆重天,好用的時候真好用,難用的時候讓人想砸電腦!!

專案原始碼