Android Bottom Sheet詳解

轉載自:http://blog.csdn.net/qibin0506/article/details/51002241

最近Android更新了support library, 版本到了23.2, 從官方blog中我們還是可以看到幾個令人心動的特性的,例如夜間模式的支持,BottomSheet.今天我們就來介紹一下這個Bottom Sheet,這可能會給我們開發中需要的一些效果帶來便利.

雖然這裏我們準備用整整一篇博客的時間來介紹它,不過這東西使用起來太簡單了也太方便了,這還要感謝Behavior機制的引入,我記得在博客源碼看CoordinatorLayout.Behavior原理中說過,Behavior其實是CoordinatorLayout 
的核心內容,Behavior允許我們在不用自定義控件的前提下實現一些效果,Bottom Sheet正是通過Behavior實現的.

首先我們來看一個效果,

這個效果的實現很簡單,甚至基本不需要Java代碼,我們只需要給我們的下面的這個可滑動的view一個behavior就ok,把這個behavior指定爲android.support.design.widget.BottomSheetBehavior就可以達到這種效果了,是不是很簡單? 來看看代碼吧,

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    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:fitsSystemWindows="true"
    tools:context="org.loader.bottomsheetmodule.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize" />

    </android.support.design.widget.AppBarLayout>

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

        <Button
            android:layout_gravity="center_horizontal"
            android:onClick="intro"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="介紹"/>

        <Button
            android:layout_gravity="center_horizontal"
            android:onClick="select"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="選擇"/>

    </LinearLayout>

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/scroll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

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

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="50dp"
                android:background="@color/colorPrimary"
                android:text="人不會死在絕境,卻往往栽在十字路口"
                android:textColor="@android:color/white"/>

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

看到NestedScrollView的behavior了嗎? 我們僅僅指定了一下他的值就可以了,其他的地方沒有任何特殊的. 
雖然說我們不需要任何java代碼就可以實現,不過這裏我們還是希望可以通過按鈕去控制它,從底部滑出畢竟太隱藏了,沒有幾個人可以猜到.

public void intro(View view) {
    BottomSheetBehavior behavior = BottomSheetBehavior.from(findViewById(R.id.scroll));
    if(behavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
        behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }else {
        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

代碼也很簡單,首先我們從NestedScrollView上獲取到他的Behavior,因爲我們知道是 BottomSheetBehavior,所以這裏直接死用BottomSheetBehavior.from方法來獲取,然後通過getState方法來判斷現在的狀態,如果是展開的狀態,我們就讓它收縮起來,反之,展開它.

我們還可以給BottomSheetBehavior一個callback來監聽狀態,

behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {

    }

    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

這個確實簡單,不過有沒有發現它的用戶不是那麼的廣,接下來我們就要來介紹一個用戶相對來說廣泛點的BottomSheetDialog,這個Dialog可以實現什麼效果呢? 舉個例子吧,現在我們在商城相關的app,當我們點擊購買的時候需要選擇一下要購買的商品的屬性,以前我們可能是在底部彈出一個Popupwindow來實現,現在好了,我們可以利用BottomSheetDialog輕鬆的實現這個功能了.首先繼續來看看效果吧.

這裏是一個含有一個List的dialog,當我們點擊按鈕顯示的時候,它會出現一部分,當我們拖動它的時候,他會佔滿屏幕,現在我們就來看一下代碼如何實現,

public void select(View view) {
    RecyclerView recyclerView = (RecyclerView) LayoutInflater.from(this)
            .inflate(R.layout.list, null);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    Adapter adapter = new Adapter();
    recyclerView.setAdapter(adapter);

    final BottomSheetDialog dialog = new BottomSheetDialog(this);
    dialog.setContentView(recyclerView);
    dialog.show();
    adapter.setOnItemClickListener(new Adapter.OnItemClickListener() {
        @Override
        public void onItemClick(int position, String text) {
            Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
            dialog.dismiss();
        }
    });
}

static class Adapter extends RecyclerView.Adapter<Adapter.Holder> {

    private OnItemClickListener mItemClickListener;

    public void setOnItemClickListener(OnItemClickListener li) {
        mItemClickListener = li;
    }

    @Override
    public Adapter.Holder onCreateViewHolder(ViewGroup parent, int viewType) {
        View item = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        return new Holder(item);
    }

    @Override
    public void onBindViewHolder(final Adapter.Holder holder, int position) {
        holder.tv.setText("item " + position);
        if(mItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mItemClickListener.onItemClick(holder.getLayoutPosition(),
                            holder.tv.getText().toString());
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return 50;
    }

    class Holder extends RecyclerView.ViewHolder {
        TextView tv;
        public Holder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.text);
        }
    }

    interface OnItemClickListener {
        void onItemClick(int position, String text);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

別看代碼長,主要是Adapter的代碼!而且沒有任何難度!我們來看select方法,這個方法中我們通過LayoutInflater加載了一個佈局,這個佈局很簡單,就是一個RecyclerView.接下來的幾行代碼是配置RecyclerView和它的Adapter,相信不用多說大家也已經很熟悉了.關鍵是繼續往下的3行代碼,首先我們new了一個BottomSheetDialog,然後通過setContentView方法把我們inflate進來的佈局設置到這個dialog上,最後調用dialog的show方法將dialog顯示出來,這個效果就是這麼容易就實現了,這個dialog特性的代碼我們一行也沒有寫,android都已經幫我們完成好了.最後我們還在item的click事件中將這個dialog隱藏掉了.

好了,今天這篇博客很簡單,主要是最新的support包中這個bottomSheet的使用,以後大家在項目中又可以多一種實現dialog的方式了, 趕緊嘗試一下吧.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章