简介

在我们的开发中经常会遇到从底部弹出对话框的需求。在design包中,官方为我们提供了一种实现,就是BottomSheetDialog。它的使用和dialog一样,看下它的继承关系就知道了。

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

下面我们看下简单的使用代码。

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

是的。你没有看错,这些代码就够了。

BottomSheetDialog的兄弟还有个BottomSheetDialgFragment,来看下BottomSheetDialogFragment的代码。

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

是的。你还是没有看错,这就是全部的BottomSheetDialogFragment的代码。内部就是个BottomSheetDialog,就不做过多说明了。

代码实现

我们打开`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()方法。

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。代码如下:

                            

这里就是一个FrameLayout嵌套了个CoordinatorLayout,再嵌套了一个View用于点击收起Dialog和底部的FrameLayout用来显示我们为BottomSheetDialog设置的视图。上面wrapInBottomSheet()也就大致完了。

那么到底是怎么做到从底部弹出的呢?这边就那几行没说的了嘛。还用想,肯定是他们“搞的鬼”。

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 extends CoordinatorLayout.Behavior {...}

这是官方的解释。主要是用来和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的使用

更多相关文章

  1. 【Android(安卓)Developers Training】 79. 连接到网络
  2. Android获取常用辅助方法(获取屏幕高度、宽度、密度、通知栏高度
  3. Android弹出DatePickerDialog并获取值的方法
  4. android Cursor的自动管理方式
  5. (1)LruCache原理分析
  6. android动态获取权限方法
  7. Android布局之二——Relative Layout
  8. Android之Handler与线程
  9. 【Android(安卓)动画】帧动画、补间动画、属性动画

随机推荐

  1. PyTorch入门到进阶 实战计算机视觉与自然
  2. 算法训练营
  3. iOS逆向与安全
  4. 让nginx日志支持json格式
  5. Flutter高级进阶实战 仿哔哩哔哩APP
  6. 外显子组测序数据分析
  7. 组蛋白修饰预测基因表达
  8. 对复杂网络节点重要性的排序方法
  9. 无义介导的mRNA衰变是有意义的
  10. 互联网测试校招系列2:准备越充分,机会越大!