DialogFragment制作一个bottom dialog 踩坑实录

效果图

可以看到这个弹框是一个宽度充满整个屏幕,而且,弹框的底部还有一个灰色蒙版遮罩,实际上,弹出还有一个从下而上的动画,显得没有那么的生硬。

我在网上看到的方式都或多或少的有些缺陷,比如,要么没有灰色的蒙版要么就是宽度不是铺满整个屏幕
实际上,通过研究:

发现不能填充整个屏幕,是因为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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容