BottomSheetDialog是原生实现的BottomSheet的dialog模式,适合很多场景下的底部弹窗功能,在此次记录下踩坑内容。
BottomSheetDialog内部的布局实现及其简单,就是一个对CoordinatorLayout
的运用,XML原文如下:
其中id为design_bottom_sheet就是我们在调用setContentView()方法时往里塞的view的父布局,因此这个布局也就和实现圆角有关系了。
网上其实有好多方法介绍如何让背景透明起来的
方法基本都是以下两种:
mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));
mDialog.getWindow().findViewById(R.id.design_bottom_sheet)
.setBackgroundResource(android.R.color.transparent);
实际上可能在某些版本上可用,但是在笔者实际测试以后,发现这两个操作都没有实际上生效
明显可以看出是有个灰色的阴影效果无法去除,
最终,解决方案是:
if (mDialog.getWindow() != null) {
WindowManager.LayoutParams params = mDialog.getWindow().getAttributes();
params.dimAmount = 0.0f;
mDialog.getWindow().setAttributes(params);
}
这样设置下自己的dialog之后,就可以去掉那层灰色的样式了
这种情况下,就实现了没有阴影效果的底部弹出框了。
很多时候我们不止要实现底部弹窗,还要实现底部弹窗的圆角,那么该怎么处理呢?
其实只要在setContentView()放入的view的父布局加上需要的圆角shape就OK了
这个shape的圆角还有不懂怎么加的同学们请自觉百度吧
有的时候我们会改变一下底部弹窗的颜色,那么就会出现这个问题了
弹窗的圆角下班还有一点点白色,有经验的同学一看就明白了,那是因为咱们的view底部还有一个白色的父布局,这个父布局其实就是之前说的id是design_bottom_sheet的FrameLayout了,那么简单的处理一下就OK了
FrameLayout bottom = mDialog.findViewById(R.id.design_bottom_sheet);
if (bottom != null) {
bottom.setBackgroundResource(android.R.color.transparent);
}
这样把白色的父布局就会被处理掉了,咱们的圆角就比较合理的展示出来了。
然后,由于北京是透明的了,那么其实合理的运用一下padding和margin,就可以实现悬浮层的效果,这里就不赘述了。
这个dialog又一个很有趣的现象,就是可以折叠,因为内部毕竟是一个
CoordinatorLayout实现的嘛,其实折叠主要是靠BottomSheetBehavior来进行的操作
BottomSheetBehavior<View> behavior = BottomSheetBehavior.
from((View) mDialogContentView.getParent());
可以通过这个方法来控制默认不折叠:
behavior.setSkipCollapsed(true);
这个方法用来控制可以全部收起,就是折叠之后在往下拉就会整个底部收起来:
behavior.setHideable(true);
这个方法来控制最小折叠高度:
behavior.setPeekHeight(xxx);
那么就有些同学发现,其实我默认展开之后,下拉会折叠到一个高度,然后需要再次下拉才能完全隐藏,那么怎么来取消这个方式呢,简单的来说就是通过上边的代码来实现的了,只要将这个方法的参数传入屏幕高度,那么就不会再有下拉会折叠一下的效果了
Display defaultDisplay = activity.getWindowManager().getDefaultDisplay();
Point point = new Point();
defaultDisplay.getSize(point);
behavior.setPeekHeight(point.y);
这样会隐藏底部弹出的那部分界面,但是没有真正的dismiss 当前的dialog
所以还需要加入以下监听,来隐藏dialog:
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
//当完全隐藏时,直接消除dialog
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
mDialog.dismiss();
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
很多时候我们隐藏软键盘会调用:
InputMethodManager imm = null;
imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (getWindow() != null) {
view = getWindow().getCurrentFocus();
}
if (null != view && imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
这种方法,但是在BottomSheetDialog的EditText使用时,会出现一个很有意思的问题,那就是view = getWindow().getCurrentFocus();这个返回的是null
那么实际隐藏软件盘的操作就是失败的了
如何避免这个问题呢,目前我使用的是自定义的BottomSheetDialog,通过这个dialog来处理隐藏
public class KeyBoardBottomSheetDialog extends BottomSheetDialog {
public KeyBoardBottomSheetDialog(@NonNull Context context) {
super(context);
}
public KeyBoardBottomSheetDialog(@NonNull Context context, int theme) {
super(context, theme);
}
protected KeyBoardBottomSheetDialog(@NonNull Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
@Override
public void dismiss() {
//因为dismiss之后当前焦点的EditText无法获取,所以自定义一下
hideKeyBoard();
super.dismiss();
}
public void hideKeyBoard() {
View view = null;
InputMethodManager imm = null;
imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (getWindow() != null) {
view = getWindow().getCurrentFocus();
}
if (null != view && imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}
这样,只要调用自定义dialog的hideKeyBoard()方法,就可以实现
,就可以实现隐藏软键盘了。