Skip to content

底部对话框 BottomDialog 和底部菜单 BottomMenu

Kongzue edited this page Aug 15, 2022 · 31 revisions

底部对话框 BottomDialog 和底部菜单 BottomMenu

底部对话框 BottomDialog 和底部菜单 BottomMenu

底部对话框 BottomDialog 提供从底部弹出显示的对话框样式,可设置标题、提示文本和自定义布局,使用 Material 主题时还会提供向下滑动关闭和向上滑动展开的功能。

底部菜单 BottomMenu 则是底部对话框 BottomDialog 的扩展组件,在底部对话框的基础上额外提供了菜单功能,菜单可设置菜单内容/菜单图标/单选功能,在不同的主题下还可以提供“取消”关闭按钮(注:因 Material 直接可以下滑关闭因此 Material 主题不提供额外的“取消”关闭按钮)

显示一个简单底部对话框

使用以下代码显示一个对话框:

BottomDialog.show("标题", "这里是对话框内容。");

请注意,Material 主题的底部对话框默认是通过下滑操作来进行关闭的,不同主题处理逻辑可能不同,例如在iOS主题中,则是提供“取消”按钮来进行关闭。

在其他主题中你可以通过.setCancelButton(...)方法来设置取消按钮的文字和事件

BottomDialog.show("标题", "这里是对话框内容。")
    .setCancelButton("取消", new OnDialogButtonClickListener<BottomDialog>() {
        @Override
        public boolean onClick(BottomDialog baseDialog, View v) {
            //...
            return false;
        }
    });

显示一个底部菜单

底部菜单是基于底部对话框扩展实现的一个快速选择菜单对话框,你可以通过传入List<String>String[] menuListList<CharSequence> menuList或者CharSequence[] menuList来快速显示一个菜单:

BottomMenu.show(new String[]{"新标签页中打开", "稍后阅读", "复制链接网址"})
        .setMessage("这里是标题")
        .setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
            @Override
            public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
                toast(text);
                return false;
            }
        });

上述代码中,OnMenuItemClickListener回调是菜单的点击事件回调,其中 text 为菜单文本,index 为菜单的索引。

单选菜单也可以轻松设置菜单图标,我们尽可能的省去编写 Adapter 适配器的麻烦,要设置菜单图标可以实现一个回调setOnIconChangeCallBack(...)即可:

BottomMenu.show(new String[]{"添加", "查看", "编辑", "删除"})
        .setOnIconChangeCallBack(new OnIconChangeCallBack(true) {
            @Override
            public int getIcon(BottomMenu bottomMenu, int index, String menuText) {
                switch (menuText) {
                    case "添加":
                        return R.mipmap.img_dialogx_demo_add;
                    case "查看":
                        return R.mipmap.img_dialogx_demo_view;
                    case "编辑":
                        return R.mipmap.img_dialogx_demo_edit;
                    case "删除":
                        return R.mipmap.img_dialogx_demo_delete;
                }
                return 0;
            }
        })
        .setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
            @Override
            public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
                toast(text);
                return false;
            }
        });

上述代码中,OnIconChangeCallBack 存在一个参数(boolean)autoTintIconInLightOrDarkMode 用于识别是否需要将图标进行相应的染色,以适应亮色和暗色模式的变化,设置为 true 时代表,处于亮暗色模式下,菜单图标会自动根据文字颜色进行染色,当使用非多彩图标的线性/面性图标时,建议开启此功能。

另外,底部菜单也提供单选功能,你可以设置一个已选择的 index 索引,那么在 BottomMenu 显示时,相应位置的菜单会被选中,不同主题的选择效果略有不同。

private int selectMenuIndex;

BottomMenu.show(new String[]{"拒绝", "询问", "始终允许", "仅在使用中允许"})
        .setMessage("这里是权限确认的文本说明,这是一个单选的演示菜单")
        .setTitle("获得权限标题")
        .setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
            @Override
            public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
            	//记录已选择值
                selectMenuIndex = index;
                toast(text);
                return false;
            }
        })
        .setSelection(selectMenuIndex);		//指定已选择的位置

同样的,当您在OnMenuItemClickListener中返回值设置return true时,点击菜单后不会自动关闭。

生命周期回调

想要监控对话框的生命周期,可以实现其 接口,建议使用build()方法构建对话框:

BottomMenu.build()
        .setDialogLifecycleCallback(new DialogLifecycleCallback<BottomMenu>() {
            @Override
            public void onShow(BottomMenu dialog) {
                //对话框启动时回调
            }
            @Override
            public void onDismiss(BottomMenu dialog) {
                //对话框关闭时回调
            }
        })
        .show();

自定义布局

BottomDialog 原生参数支持自定义布局,你可以通过如下代码自定义底部对话框布局:

BottomDialog.show("标题", "这里是对话框内容。\n底部对话框也支持自定义布局扩展使用方式。",
        new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
            @Override
            public void onBind(BottomDialog dialog, View v) {
                //v.findViewById...
            }
        });

BottomMenu 菜单需要使用如下代码加入自定义布局:

BottomMenu.show(new String[]{"新标签页中打开", "稍后阅读", "复制链接网址"})
        .setMessage("菜单标题")
        .setOnMenuItemClickListener(new OnMenuItemClickListener<BottomMenu>() {
            @Override
            public boolean onClick(BottomMenu dialog, CharSequence text, int index) {
                toast(text);
                return true;
            }
        })
        .setCustomView(new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
            @Override
            public void onBind(BottomDialog dialog, View v) {
                //v.findViewById...
            }
        });

回调参数中,v 为您给定的布局文件的实例化组件,您可以通过 v.findViewById(resId)来实例化其他子布局组件,并在 onBind 方法中设置其功能和事件回调。

其他额外方法

//强制重新刷新界面
.refreshUI();

//关闭对话框
.dismiss();

//是否允许点击外部区域或返回键关闭
.setCancelable(boolean);

//设置标题文字样式
.setTitleTextInfo(TextInfo);

//设置消息文字样式
.setMessageTextInfo(TextInfo);

//设置按钮文字样式
.setCancelTextInfo(TextInfo);
    
//设置返回按键回调
.setOnBackPressedListener(OnBackPressedListener);

//获取对话框实例化对象,您可以通过此方法更深度的定制Dialog的功能
.getDialogImpl()

//获取自定义布局实例
.getCustomView()
    
//设置背景颜色,强行对对话框背景进行染色,请注意参数为int类型的颜色值而非R.color的索引
.setBackgroundColor(ColorInt);

//设置菜单文本样式
.setMenuTextInfo(TextInfo)

//设置对话框圆角(会裁切内容显示,此设置在 BottomDialog 和 BottomMenu 中只影响左上、右上两个角的圆角)
.setRadius(float px)

背景遮罩

BottomDialog 支持修改背景遮罩,这是为了丰富扩展性。如果需要背景遮罩,您可以自行使用如下代码设置:

bottomDialog.setMaskColor(colorInt);

请注意,传入参数为 ColorInt 值,您可以使用 Color.parseColor("#4D000000") 设置一个 HEX 色值,或使用 getResources().getColor(R.color.black30) 设置一个颜色的资源值。

额外组件

TextInfo

TextInfo 用于存储基础文本样式设置,其包含一系列属性和响应的 get/set 方法,例如方法解释如下:

属性 解释 默认值
fontSize 字号大小,值为-1时使用默认样式,单位:dp -1
gravity 对齐方式,值为-1时使用默认样式,取值可使用Gravity.CENTER等对齐方式 -1
fontColor 文字颜色,值为1时使用默认样式,取值可以用Color.rgb(r,g,b)等方式获取 1
bold 是否粗体 false

关于“滑动提示条”

在使用 Material 主题风格且底部对话框,默认是可滑动关闭的,且当 cancelable 值为 true 时,会在对话框顶部显示一个 “滑动提示条”,若依据您的需求需要隐藏其显示,可通过以下方式关闭:

方式一,针对单次有效的方案

借助 DialogX 暴露内部元素的特性,删除 tab 布局。

BottomDialog.show("标题", "这里是对话框内容。\n底部对话框也支持自定义布局扩展使用方式。",
        new OnBindView<BottomDialog>(R.layout.layout_custom_view) {
            @Override
            public void onBind(BottomDialog dialog, View v) {
                if (dialog.getDialogImpl().imgTab != null) {
                    ((ViewGroup) dialog.getDialogImpl().imgTab.getParent()).removeView(dialog.getDialogImpl().imgTab);
                }
                //...
            }
        });

方式二,重写布局

手动创建一个 layout_dialogx_bottom_material 的布局(暗色对应 layout_dialogx_bottom_material_dark),内容请参考 layout_dialogx_bottom_material.xml(暗色对应 layout_dialogx_bottom_material_dark.xml

修改删除其中 <ImageView id="@+id/img_tab"> 的布局:

<ImageView
    android:id="@+id/img_tab"
    android:layout_width="30dp"
    android:layout_height="4dp"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="10dp"
    android:src="@drawable/rect_dialogx_material_dialogtap" />

此方案利用的是对资源的重写方式完成修改,请无需担心空指针,DialogX 内部有做对应处理。

单独指定样式

若你的 App 引入了多种主题,在特定场景下需要使对话框显示为某种非全局的主体样式,可使用 .build() 构建对话框,然后使用 .setStyle(style) 来指定主题样式,在最后执行 .show() 命令显示对话框,例如:

BottomDialog.build()
        //或直接使用 .build(IOSStyle.style())
        .setStyle(IOSStyle.style())
        .setTitle("Title")
        .setMessage("Message content.")
        .setOkButton("OK")
        .show();
Clone this wiki locally