这三种dialog,在Android 开发中经常会使用到,基本用法网络上也有很多,下面主要阐述一下我在项目中遇到的坑以及对应的解决办法
BottomSheetDialog
issue :
BottomSheetDialog 弹出时,阴影无法覆盖到状态栏,导致状态栏还是默认的背景色
处理方法:
在oncreate 的时候重新计算并设置window 窗口的高度
public class T3BottomSheetDialog extends BottomSheetDialog {
public T3BottomSheetDialog(@NonNull Context context) {
super(context);
}
public T3BottomSheetDialog(@NonNull Context context, int theme) {
super(context, theme);
}
protected T3BottomSheetDialog(@NonNull Context context,
boolean cancelable,
OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int statusBarHeight = getStatusBarHeight(getContext());
int dialogHeight = DisplayUtil.getScreenH(getContext()) - statusBarHeight;
getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, dialogHeight == 0 ? ViewGroup
.LayoutParams.MATCH_PARENT : dialogHeight);
}
private static int getStatusBarHeight(Context context) {
int statusBarHeight = 0;
Resources res = context.getResources();
int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = res.getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
}
项目中使用方法:
private void showSelectPhotoDialog() {
if (mBottomSheetDialog == null) {
mBottomSheetDialog = new T3BottomSheetDialog(getContext());
mBottomSheetDialog.setContentView(R.layout.dialog_photo_selector);
mBottomSheetDialog.getWindow().findViewById(R.id.design_bottom_sheet)
.setBackgroundResource(android.R.color.transparent);
mBottomSheetDialog.findViewById(R.id.dialog_cancel_button)
.setOnClickListener(v -> mBottomSheetDialog.dismiss());
mBottomSheetDialog.findViewById(R.id.dialog_from_album_button).setOnClickListener(v -> {
mBottomSheetDialog.dismiss();
requestPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
this::singleAlbum, getString(R.string.album_permission_needed));
});
mBottomSheetDialog.findViewById(R.id.dialog_take_photo_button).setOnClickListener(v -> {
mBottomSheetDialog.dismiss();
if (!checkPermission()) {
new TwoSelectorDialog(getContext(), "权限获取", "是否允许程序调用摄像头权限用于头像拍照", "取消",
"允许").setCancelClickListener(Dialog::dismiss).setConfirmClickListener(exSweetAlertDialog -> {
exSweetAlertDialog.dismiss();
requestPermission(new String[]{Manifest.permission.CAMERA},
this::takePhoto, getString(R.string.camera_permission_needed));
}).show();
} else {
requestPermission(new String[]{Manifest.permission.CAMERA}, this::takePhoto,
getString(R.string.camera_permission_needed));
}
});
}
mBottomSheetDialog.show();
}
这里需要注意的一点必选在setContentView之后才可以设置背景
DialogFragment
DialogFragment 分为 普通Dialog 样式和全屏dialog样式
普通Dialog 样式
主要在onCreateView 中设置相应的dialog 样式
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.windowAnimations = R.style.ad_dialog_anim;
getDialog().getWindow().setAttributes(params);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getDialog().setCanceledOnTouchOutside(false);
并在 onStart 中设置Dialog 对应的宽高,这样默认就在window 窗口中间显示
Dialog dialog = getDialog();
if (dialog != null)
dialog.getWindow()
.setLayout((int) (ScreenUtils.getScreenSizePoint().x * 0.8),
ViewGroup.LayoutParams.WRAP_CONTENT);
}
全屏Dialog 样式
我找了很久始终不能让其全屏显示,最后发现如下方式
同样在onCreateView中
getDialog().getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
在onStart中
Dialog dialog = getDialog();
if (dialog != null) {
dialog.getWindow()
.setLayout( ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
最后封装一下
public abstract class BaseDialogFragment extends DialogFragment {
@Inject
UserRepository mUserRepository;
protected View mView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.windowAnimations = R.style.ad_dialog_anim;
getDialog().getWindow().setAttributes(params);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
if (isFullScreen()) {
getDialog().getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
getDialog().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getDialog().setCanceledOnTouchOutside(false);
mView = inflater.inflate(getLayoutId(), null);
initView();
initDatas();
return mView;
}
protected abstract int getLayoutId();
protected abstract void initDatas();
protected abstract void initView();
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
if (isFullScreen()){
dialog.getWindow()
.setLayout( ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
}else {
dialog.getWindow()
.setLayout((int) (ScreenUtils.getScreenSizePoint().x * 0.8),
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
}
public boolean isFullScreen() {
return false;
}
/**
* 是否可以取消
*
* @param cancelEnable
*/
public void setCancelEnable(boolean cancelEnable) {
setCancelable(cancelEnable);
getDialog().setCanceledOnTouchOutside(cancelEnable);
}
}
具体子类继承该类,并实现是否是全屏展示,默认不是全屏展示
BottomSheetDialogFragment
BottomSheetDialogFragment 默认不处理的滑动方式,是先展开一部分,需要手动滑动,才能完整的展开其余内容,项目需求是直接展开全部内容,可以在onStart进行相关处理
public abstract class T3BottomSheetDialogFragment extends BottomSheetDialogFragment {
protected View mView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mView = inflater.inflate(getLayoutId(), container, false);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
initView();
initData();
return mView;
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
}
final View view = getView();
view.post(() -> {
View parent = (View) view.getParent();
CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) (parent).getLayoutParams();
CoordinatorLayout.Behavior behavior = params.getBehavior();
BottomSheetBehavior bottomSheetBehavior = (BottomSheetBehavior) behavior;
bottomSheetBehavior.setPeekHeight(view.getMeasuredHeight());
parent.setBackgroundColor(Color.TRANSPARENT);
});
}
}
这里会存在另一个问题,就是在点击外部区域的时候,不能自动dismiss 对话框,我使用了一个讨巧的办法,使用了全屏
bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
并在具体实现类对外部view的点击事件进行了处理
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="@+id/id_top_layout1"
android:layout_width="match_parent"
android:layout_height="55dp" />
<View
android:id="@+id/id_top_layout2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shaper_white_corner_5"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="52dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="指派车辆"
android:textColor="#000"
android:textSize="16dp" />
<ImageView
android:id="@+id/close_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="12dp"
android:padding="5dp"
android:src="@drawable/icon_common_cancel" />
</RelativeLayout>
<RelativeLayout
android:minHeight="100dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:visibility="gone"
android:id="@+id/car_list_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
这里预留了dialog 到屏幕顶部的最小高度 55 dp
<View
android:id="@+id/id_top_layout1"
android:layout_width="match_parent"
android:layout_height="55dp" />
然后监听了id_top_layout1,id_top_layout2 的touch 事件,一旦触摸直接dismiss 对话框
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
dismiss();
}
return false;
}