Skip to content

高阶扩展用法

Kongzue edited this page Sep 14, 2024 · 10 revisions

🌐 View English Document | 繁體中文文檔

🆙高阶扩展用法

DialogX 结构图

DialogX 结构图

单独针对组件生效的属性

尽管已经有全局的配置,但开发者依然可以单独针对某一个组件进行一些设置。

例如如果全局配置为禁止使用点击外部区域关闭对话框,而要 BottomDialog 例外,那么可以使用如下配置:

BottomDialog.overrideCancelable = BaseDialog.BOOLEAN.TRUE;

还可以针对组件的动画进行单独设置,例如:

BottomDialog.overrideEnterDuration = 100;    //入场动画时长为100毫秒
BottomDialog.overrideExitDuration = 100;     //出场动画时长为100毫秒
BottomDialog.overrideEnterAnimRes = R.anim.anim_dialogx_top_enter;  //入场动画资源
BottomDialog.overrideExitAnimRes = R.anim.anim_dialogx_top_exit;    //出场动画资源

这样的方法单独对某一个组件进行进出场动画的重写设置。注意这些方法不会影响全局其他组件,只是单独设置单一组件的动画效果。

优先级为:实例使用方法设置 > 组件override设置 > 全局设置。

另外 FullScreenDialog 只提供动画时长设置,不提供动画资源设置(此组件只允许上下进出场动画);

CustomDialog 额外拥有了 overrideMaskEnterAnimResoverrideMaskExitAnimRes,可以覆盖背景遮罩的动画效果,设置为 0 时取消动画。

此时,在当前项目中其他的对话框组件将依然遵循全局配置,而单独针对组件生效的属性的对话框则会以单独属性设置为主。

注意此配置要区别于针对单一对话框实例的属性设置,例如:

BottomDialog.build()
        ...
        .setCancelable(true)   
        .show();

重写部分主题

例如想要将 PopTip 吐司提示不按照主题的设定(例如屏幕底部)显示,而是以自己的要求显示(例如屏幕中央),但对于 PopTip 的 align 属性属于主题控制的,此时可以通过重写主题来调整对话框的部分行为,例如:

DialogX.globalStyle = new MaterialStyle(){
    @Override
    public PopTipSettings popTipSettings() {
        return new PopTipSettings() {
            @Override
            public ALIGN align() {
                return ALIGN.CENTER;
            }
        };
    }
};

完全自定义开启、关闭动画

请注意此方法针对的是需要对对话框内容组件和细节完全自行控制的情况,如果你只是想改变整体动画而不需要控制细节那么请参阅某种对话框的自定义进入和关闭动画章节,例如 《基础对话框 MessageDialog 和 输入对话框 InputDialog - 自定义进入和关闭动画》

使用 DialogXAnimInterface 接口可以完全自定义开启、关闭动画。

由于 DialogX 对话框组件的内部元素都是暴露的,你可以轻松获取并访问内部实例,利用这一点,再加上 DialogXAnimInterface 会负责对话框启动和关闭的动画行为,你可以充分利用它实现你想要的效果。

例如对于一个 CustomDialog,你可以这样控制其启动和关闭动画:

CustomDialog.show(new OnBindView<CustomDialog>(R.layout.layout_custom_dialog) {
            @Override
            public void onBind(final CustomDialog dialog, View v) {
                //...
            }
        })
        //实现完全自定义动画效果
        .setDialogXAnimImpl(new DialogXAnimInterface<CustomDialog>() {
            @Override
            public void doShowAnim(CustomDialog customDialog, ViewGroup dialogBodyView) {
                Animation enterAnim;
                int enterAnimResId = com.kongzue.dialogx.R.anim.anim_dialogx_top_enter;
                enterAnim = AnimationUtils.loadAnimation(me, enterAnimResId);
                enterAnim.setInterpolator(new DecelerateInterpolator(2f));
                long enterAnimDurationTemp = enterAnim.getDuration();
                enterAnim.setDuration(enterAnimDurationTemp);
                customDialog.getDialogImpl().boxCustom.startAnimation(enterAnim);
                ValueAnimator bkgAlpha = ValueAnimator.ofFloat(0f, 1f);
                bkgAlpha.setDuration(enterAnimDurationTemp);
                bkgAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        if (customDialog.getDialogImpl() == null || customDialog.getDialogImpl().boxRoot == null) {
                            return;
                        }
                        customDialog.getDialogImpl().boxRoot.setBkgAlpha((Float) animation.getAnimatedValue());
                    }
                });
                bkgAlpha.start();
            }
            @Override
            public void doExitAnim(CustomDialog customDialog, ViewGroup dialogBodyView) {
                int exitAnimResIdTemp = com.kongzue.dialogx.R.anim.anim_dialogx_default_exit;
                Animation exitAnim = AnimationUtils.loadAnimation(me, exitAnimResIdTemp);
                customDialog.getDialogImpl().boxCustom.startAnimation(exitAnim);
                ValueAnimator bkgAlpha = ValueAnimator.ofFloat(1f, 0f);
                bkgAlpha.setDuration(exitAnim.getDuration());
                bkgAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        if (customDialog.getDialogImpl() == null || customDialog.getDialogImpl().boxRoot == null) {
                            return;
                        }
                        customDialog.getDialogImpl().boxRoot.setBkgAlpha((Float) animation.getAnimatedValue());
                    }
                });
                bkgAlpha.start();
            }
        });

对于 animProgress 它本质上是个反向回调执行器,因为动画时长不定,你需要通知 DialogX 当前你的动画到达哪个阶段了,对话框需要根据这个阶段进行操作处理,例如关闭动画执行过程应当是 1f 至 0f 的过程,完毕后应当销毁对话框,那么当 animProgress.run(0f) 时就会执行销毁流程,而启动动画应当是 0f 至 1f 的过程,当 animProgress.run(1f) 时启动对话框的动画完全执行完毕。

队列对话框

某些场景下需要有“模态”对话框的需要,即,一次性创建多个对话框,组成队列,逐一显示,当上一个对话框关闭时自动启动下一个对话框,此时可以使用队列对话框来完成。

示例代码如下,在 DialogX.showDialogList(...) 中构建多个对话框,请注意这些对话框必须是没有启动的状态,使用 .build() 方法完成构建,以 “,” 分隔组成队列,即可自动启动。

DialogX.showDialogList(
        MessageDialog.build().setTitle("提示").setMessage("这是一组消息对话框队列").setOkButton("开始").setCancelButton("取消")
                .setCancelButton(new OnDialogButtonClickListener<MessageDialog>() {
                    @Override
                    public boolean onClick(MessageDialog dialog, View v) {
                        dialog.cleanDialogList();
                        return false;
                    }
                }),
        PopTip.build().setMessage("每个对话框会依次显示"),
        PopNotification.build().setTitle("通知提示").setMessage("直到上一个对话框消失"),
        InputDialog.build().setTitle("请注意").setMessage("你必须使用 .build() 方法构建,并保证不要自己执行 .show() 方法").setInputText("输入文字").setOkButton("知道了"),
        TipDialog.build().setMessageContent("准备结束...").setTipType(WaitDialog.TYPE.SUCCESS),
        BottomDialog.build().setTitle("结束").setMessage("下滑以结束旅程,祝你编码愉快!").setCustomView(new OnBindView<BottomDialog>(R.layout.layout_custom_dialog) {
            @Override
            public void onBind(BottomDialog dialog, View v) {
                ImageView btnOk;
                btnOk = v.findViewById(R.id.btn_ok);
                btnOk.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                                        dialog.dismiss();
                                    }
                });
            }
        })
);

使用过程中,随时可以使用 .cleanDialogList() 来停止接下来的队列对话框的显示。

实现模式(实验性)

Window 实现模式

DialogX 默认使用 View 实现模式,自适应生命周期,你也可以选择 Window 的实现方案(与 AlertDialog 类似),请注意,使用 Window 实现模式是实验性质的,且存在一定的风险和已知 bug,你可以使用以下方法启用 Window 实现模式:

DialogX.implIMPLMode= DialogX.IMPL_MODE.WINDOW;

WindowUtil 提供了额外自定义WindowManager.LayoutParams的接口:

WindowUtil.windowSettings = new WindowUtil.WindowSettings() {
    @Override
    public WindowManager.LayoutParams overrideWindowLayoutParamsInterface(Context context, View dialogView, WindowManager.LayoutParams originWindowLayoutParams) {
        //处理 originWindowLayoutParams...
        return originWindowLayoutParams;
    }

    @Override
    public ViewGroup overrideRootView(Context context) {
        //自定义根布局,对话框布局会被添加到根布局中,返回 null 代表使用默认的 FrameLayout
        return null;
    }
};

DialogFragment 实现方式

在最新的版本 0.0.41.beta4 中,提供了 DialogFragment 实现方式,使用以下方法启用 DialogFragment 实现:

DialogX.implIMPLMode= DialogX.IMPL_MODE.DIALOG_FRAGMENT;

此模式下目前尚未发现待处理的问题,但依然不建议在生产环境使用。

FloatingActivity 实现方式

类似于 Window,使用一个透明底的 Activity 作为对话框的底层承担显示,这样的做法可以再一定程度上从后台启动(PendingIntent)。

DialogX.implIMPLMode= DialogX.IMPL_MODE.FLOATING_ACTIVITY;
Clone this wiki locally