BottomSheetDialogFragment 继承自 AppCompatDialogFragment,官方解释为模态底部表,是 DialogFragment 的一个版本,它使用的是 BottomSheetDialog,而不是浮动对话框。BottomSheetDialogFragment 相对于其它对话框有着以下的优势:
1、拥有自己的生命周期;
2、可对整个页面进行折叠、展开和销毁;
3、可灵活使用自定义样式。
package android.support.design.widget;
public class BottomSheetDialogFragment extends AppCompatDialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new BottomSheetDialog(getContext(), getTheme());
}
}
BottomSheetDialogFragment 的父类是 AppCompatDialogFragment,重写了 onCreateDialog() 方法,返回了一个 BottomSheetDialog 实例,该 dialog 的主题形式来自于 getTheme() 方法,getTheme() 是 DialogFragment 的公共方法。
进入 BottomSheetDialog 的源码,dialog 的装载发生在 setContentView() 中:
并且在 onStart 方法里:
因此,重写该方法可以定义 BottomSheetDialog 的初始状态。
在 design 包下,我们找到 design_bottom_sheet_dialog.xml,如下:
<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>
由上可知,装载 dialog 的容器为”design_bottom_sheet”,它指定了一个 style 。
我们可以通过自定义如下 Theme 来调整 BottomSheetDialog 的样式:bottomSheetStyle,ctrl + 单击进入该样式,再在打开的文件中搜索”bottomSheetStyle”,显示如下:
由图片可知,它引用于”@style/Widget.Design.BottomSheet.Modal”,继续进入,发现它包含了如下属性:
很明显,background 属性定义了 dialog 的背景色,因此,我们可以重新定义这些属性,如下(注意 parent=”android:Widget”):
<style name="TransparentBottomSheetStyle" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/SheetStyle
style>
<style name="SheetStyle" parent="android:Widget">
<item name="android:background">@android:color/transparent
- "behavior_peekHeight"
>auto
- "behavior_hideable"
>true
- "behavior_skipCollapsed">false
style>
有以上的分析,我们可以封装一个基类,方便后续使用。
public class BaseFullBottomSheetFragment extends BottomSheetDialogFragment {
/**
* 顶部向下偏移量
*/
private int topOffset = 0;
private BottomSheetBehavior behavior;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (getContext() == null) {
return super.onCreateDialog(savedInstanceState);
}
return new BottomSheetDialog(getContext(), R.style.TransparentBottomSheetStyle);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
// 设置软键盘不自动弹出
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
FrameLayout bottomSheet = dialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet);
if (bottomSheet != null) {
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) bottomSheet.getLayoutParams();
layoutParams.height = getHeight();
behavior = BottomSheetBehavior.from(bottomSheet);
// 初始为展开状态
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
/**
* 获取屏幕高度
*
* @return height
*/
private int getHeight() {
int height = 1920;
if (getContext() != null) {
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Point point = new Point();
if (wm != null) {
// 使用Point已经减去了状态栏高度
wm.getDefaultDisplay().getSize(point);
height = point.y - getTopOffset();
}
}
return height;
}
public int getTopOffset() {
return topOffset;
}
public void setTopOffset(int topOffset) {
this.topOffset = topOffset;
}
public BottomSheetBehavior getBehavior() {
return behavior;
}
}
在使用时,只需重写 onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 方法,传入自己的 dialog 界面:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View dialogView = inflater.inflate(R.layout.dialog_monitor_detail, container, false);
return dialogView;
}
可通过 Behavior 的方式关闭它:
if (getBehavior() != null) {
getBehavior().setState(BottomSheetBehavior.STATE_HIDDEN);
}
设置全部展开时距离顶部的偏移量:
setTopOffset(100);
由于篇幅较小,暂不上传源码至 Github,本文将对持续更新。