可以看到这个弹框是一个宽度充满整个屏幕,而且,弹框的底部还有一个灰色蒙版遮罩,实际上,弹出还有一个从下而上的动画,显得没有那么的生硬。
我在网上看到的方式都或多或少的有些缺陷,比如,要么没有灰色的蒙版,要么就是宽度不是铺满整个屏幕。
实际上,通过研究:
发现不能填充整个屏幕,是因为diaglog中window的style被这个<item name="android:windowBackground">@null</item>
属性控制了,出现了一个左右边距;
没有灰色蒙版遮罩,是因为<item name="android:backgroundDimEnabled">true</item>
这个属性是false了。
弄懂了这些个原因,去实现一个自己理想的底部弹框,就相当容易了,分为纯代码控制,和theme控制两种,theme控制的被注释了。随便你喜欢那种方式都ok,不想要动画效果把动画去掉就好。
import android.app.Dialog;
import android.app.DialogFragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
/**
* Created by brzhang on 2017/12/16.
*/
public class BaseDialogFragment extends DialogFragment {
public static BaseDialogFragment newInstance() {
Bundle args = new Bundle();
BaseDialogFragment fragment = new BaseDialogFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// SafeUtils.getStringExtra(getArguments(),"key");
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity(), R.style.AppTheme);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // must be called before set content
//dialog.setContentView(R.layout.dialog_fragment_holder);
dialog.setCanceledOnTouchOutside(true);
// 设置宽度为屏宽、靠近屏幕底部。
Window window = dialog.getWindow();
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
//以下三句代码等价于在theme中配置<item name="android:windowBackground">@null</item><item name="android:backgroundDimEnabled">true</item>
window.setBackgroundDrawable(null);
wlp.dimAmount = 0.5f;
window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
//这里可以配置弹出动画
window.setWindowAnimations(R.style.DataSheetAnimation);
return dialog;
}
/**
* 这种方式直接通过theme控制,更加方便
*
* @param savedInstanceState
* @return
*/
// @Override
// public Dialog onCreateDialog(Bundle savedInstanceState) {
// Dialog dialog = new Dialog(getActivity(), R.style.AppTheme_Dialog_Bottom);
// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // must be called before set content
// //dialog.setContentView(R.layout.dialog_fragment_holder);
// dialog.setCanceledOnTouchOutside(true);
//
// // 设置宽度为屏宽、靠近屏幕底部。
// Window window = dialog.getWindow();
// WindowManager.LayoutParams wlp = window.getAttributes();
// wlp.gravity = Gravity.BOTTOM;
// wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
// wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
// window.setAttributes(wlp);
//
// return dialog;
// }
/**
* AppTheme.Dialog.Bottom
*/
// <style name="AppTheme.Dialog.Bottom">
// <item name="android:windowAnimationStyle">@style/DataSheetAnimation</item>
// <item name="android:windowBackground">@null</item>
// <item name="android:backgroundDimEnabled">true</item>
// </style>
// <style name="DataSheetAnimation" parent="@android:style/Animation.Dialog">
// <item name="android:windowEnterAnimation">@anim/push_up_in</item>
// </style>
// <set xmlns:android="http://schemas.android.com/apk/res/android">
// <translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/>
// <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
// </set>
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_fragment_holder, container, false);
setupView();
return view;
}
private void setupView() {
//这里做一些点击事件
}
}
当然肯定有人会说,怎么不用BottomSheetDialogFragment 去做一个底部弹框的,我想说的是,BottomSheetDialogFragment有些场景不使用,比如,你要求的弹框的高度是200dp固定,里面的元素可以滑动,这时候BottomSheetDialogFragment,有些捉襟见肘了,我尝试过去拦截BottomSheetDialogFragment的touch,但是失败了,有些冲突不大容易解决,BottomSheetDialogFragment虽然好用,但是适用于contentview可以展开额情景。因此才实现了一个BottomDiaglog.