Android Design Library之四:BottomSheetDialog

簡介

在咱們的開發中常常會遇到從底部彈出對話框的需求。在design包中,官方爲咱們提供了一種實現,就是BottomSheetDialog。它的使用和dialog同樣,看下它的繼承關係就知道了。
圖片描述html

  • 本文design包使用的版本爲27.0.2

下面咱們看下簡單的使用代碼。java

BottomSheetDialog dialog = new BottomSheetDialog(this);
        dialog.setContentView(R.layout.bottom_dialog_view);
        dialog.show();

是的。你沒有看錯,這些代碼就夠了。android

BottomSheetDialog的兄弟還有個BottomSheetDialgFragment,來看下BottomSheetDialogFragment的代碼。app

public class BottomSheetDialogFragment extends AppCompatDialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new BottomSheetDialog(getContext(), getTheme());
    }

}

是的。你仍是沒有看錯,這就是所有的BottomSheetDialogFragment的代碼。內部就是個BottomSheetDialog,就不作過多說明了。ide

代碼實現

咱們打開`BottomSheetDialog的代碼查看的話會發現,實現也很簡單。只有二百行代碼。來看一下。
咱們在使用的時候會調用。setContentView()方法,這裏有三個重載的方法:函數

@Override
    public void setContentView(@LayoutRes int layoutResId) {
        super.setContentView(wrapInBottomSheet(layoutResId, null, null));
    }
    @Override
    public void setContentView(View view) {
        super.setContentView(wrapInBottomSheet(0, view, null));
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        super.setContentView(wrapInBottomSheet(0, view, params));
    }

咱們能夠看到最後都調用了wrapInBottomSheet()方法。this

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
        // #1
        final FrameLayout container = (FrameLayout) View.inflate(getContext(),
                R.layout.design_bottom_sheet_dialog, null);
        final CoordinatorLayout coordinator =
                (CoordinatorLayout) container.findViewById(R.id.coordinator);
        //#2
        if (layoutResId != 0 && view == null) {
            view = getLayoutInflater().inflate(layoutResId, coordinator, false);
        }
        //#3
        FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
        mBehavior = BottomSheetBehavior.from(bottomSheet);
        mBehavior.setBottomSheetCallback(mBottomSheetCallback);
        mBehavior.setHideable(mCancelable);
        if (params == null) {
            bottomSheet.addView(view);
        } else {
            bottomSheet.addView(view, params);
        }
            //...省略部分代碼
        return container;
    }

咱們能夠分兩部分開,#2部分就是獲取到設置的View這沒什麼好說的。 #1獲取了個design_bottom_sheet_dialogFrameLayout。代碼以下:idea

<FrameLayout
    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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <View
            android:id="@+id/touch_outside"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:importantForAccessibility="no"
            android:soundEffectsEnabled="false"
            tools:ignore="UnusedAttribute"/>

        <FrameLayout
            android:id="@+id/design_bottom_sheet"
            style="?attr/bottomSheetStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|top"
            app:layout_behavior="@string/bottom_sheet_behavior"/>

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

</FrameLayout

這裏就是一個FrameLayout嵌套了個CoordinatorLayout,再嵌套了一個View用於點擊收起Dialog和底部的FrameLayout用來顯示咱們爲BottomSheetDialog設置的視圖。上面wrapInBottomSheet()也就大體完了。spa

那麼究竟是怎麼作到從底部彈出的呢?這邊就那幾行沒說的了嘛。還用想,確定是他們「搞的鬼」。code

mBehavior = BottomSheetBehavior.from(bottomSheet);

經過這一行咱們建立了一個BottomSheetBehavior。而正式這個BottomSheetBehavior讓對話框從底部彈出的。

@Override
    protected void onStart() {
        super.onStart();
        if (mBehavior != null) {
            mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    }

Dialog展現的時候,就調用了。BottomSheetBehaviorsetState(BottomSheetBehavior.STATE_COLLAPSED),那爲何調用這個方法就能顯示出來了呢?咱們來看下BottomSheetBehavior的簡單介紹,以後咱們就明白了。

BottomSheetBehavior

/**
 * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
 * a bottom sheet.
 */
public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {...}

這是官方的解釋。主要是用來和CoordinatorLayout配合來實現底部展現效果的。
主要使用的函數是setState()方法,狀態有以下幾個:

  • STATE_DRAGGING: 被拖動的狀態。
  • STATE_SETTLING: 拖拽鬆開以後到達終點位置(collapsed or expanded)前的狀態
  • STATE_EXPANDED: 展開的狀態
  • STATE_COLLAPSED: 摺疊的狀態
  • STATE_HIDDEN: 隱藏的狀態。

在這裏主要說一下STATE_COLLAPSEDSTATE_EXPANDED的區別。 再說區別以前咱們須要先看一個參數,mPeekHeight這個參數就是用來設置STATE_COLLAPSED狀態下,界面顯示的高度的。當不設置的時候會顯示 view的所有。STATE_EXPANDED狀態下則會顯示出View的所有。還有一點須要注意的是設置STATE_HIDDEN的時候須要將mHideable設置爲true。設置mPeekHeightmHideable的方法都有兩種,分別爲:

  • set方法: setPeekHight(height) 和setHideable(hideable)
  • xml中定義參數:
app:behavior_hideable="true"
     app:behavior_peekHeight="50dp"

經過設置不一樣的狀態來展示出不一樣的效果。參考BottomSheetDialog的實現咱們就能夠實現一個本身的底部彈出效果了。獲取Behavior咱們可使用:

mBehavior = BottomSheetBehavior.from(view);

BottomSheetDialog中咱們在onStart()方法中調用了。 mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED),這個時候,咱們爲dialog設置的界面就顯示出來了。那麼爲何沒有摺疊的效果呢?由於BottomSheetDialog中並無設置mPeekHeight的值。前面說了。當沒有設置peekHeight時,STATE_COLLAPSED狀態下會顯示View的所有。

參考:
BottomSheets的使用

相關文章
相關標籤/搜索