IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 优雅地管理Dialog弹框 -> 正文阅读

[移动开发]Android 优雅地管理Dialog弹框

我们应该都知道任何一个app的UI都会遵循一个统一的样式,比如我们的Dialog、Log、Toast等,统一管理好自己的组件库,对自己或后来人都会有很大地帮助的。

记得自己刚开始接手某个项目时,发现这个项目什么规范都没有,命名啥的也不规范,虽然有一些统一管理的工具类,但是写地真是烂,唉,说多了都是泪。。。。

接下来讲解下小球项目里Dialog,我们项目中Dialog居中显示,属性有标题、内容、按钮(1或2个),如我们的布局文件dialog_common_view.xml
<?xml version="1.0" encoding="utf-8"?>
<com.flyco.roundview.RoundLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:paddingBottom="10dp"
    app:rv_backgroundColor="@color/white"
    app:rv_cornerRadius="6dp">

    <com.flyco.roundview.RoundTextView
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:gravity="center"
        android:id="@+id/tv_dialog_title"
        android:minHeight="50dp"
        android:paddingBottom="4dp"
        android:paddingEnd="15dp"
        android:paddingStart="15dp"
        android:paddingTop="4dp"
        android:text="标题"
        android:textColor="@color/dialog_title_text"
        android:textSize="17sp"
        android:textStyle="bold"
        android:visibility="visible"
        app:rv_backgroundColor="@color/dialog_title_bg"
        app:rv_cornerRadius_TL="6dp"
        app:rv_cornerRadius_TR="6dp" />

    <TextView
        android:layout_height="wrap_content"
        android:layout_marginBottom="25dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="25dp"
        android:layout_width="match_parent"
        android:gravity="center"
        android:id="@+id/tv_dialog_content"
        android:lineSpacingExtra="2dp"
        android:maxHeight="400dp"
        android:scrollbars="vertical"
        android:text="弹框内容"
        android:textColor="@color/dialog_content_text"
        android:textSize="14sp" />


    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_width="match_parent"
        android:id="@+id/ll_bottom_operation"
        android:orientation="horizontal">

        <com.flyco.roundview.RoundTextView
            android:layout_height="40dp"
            android:layout_marginEnd="4dp"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:gravity="center"
            android:id="@+id/rtv_left"
            android:text="@string/dialog_btn_cancel"
            android:textColor="@color/dialog_btn_cancel_text"
            android:textSize="14sp"
            android:visibility="visible"
            app:rv_backgroundColor="@color/dialog_btn_cancel_bg"
            app:rv_backgroundPressColor="@color/dialog_btn_cancel_bg_checked"
            app:rv_cornerRadius="6dp"
            app:rv_strokeColor="@color/dialog_btn_cancel_stroke"
            app:rv_strokePressColor="@color/dialog_btn_cancel_stroke_checked"
            app:rv_strokeWidth="1dp" />

        <com.flyco.roundview.RoundTextView
            android:layout_height="40dp"
            android:layout_marginStart="4dp"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:gravity="center"
            android:id="@+id/rtv_right"
            android:text="@string/dialog_btn_confirm"
            android:textColor="@color/dialog_btn_confirm_text"
            android:textSize="14sp"
            android:visibility="visible"
            app:rv_backgroundColor="@color/dialog_btn_confirm_bg"
            app:rv_backgroundPressColor="@color/dialog_btn_confirm_bg_checked"
            app:rv_cornerRadius="6dp" />

    </LinearLayout>
</com.flyco.roundview.RoundLinearLayout>

用到的依赖
    implementation 'com.blankj:utilcodex:1.30.6'
    implementation 'com.flyco.roundview:FlycoRoundView_Lib:1.1.4@aar'
颜色值
    <!--弹框相关颜色-->
    <color name="dialog_title_text">#101a3e</color>
    <color name="dialog_title_bg">#F9FAFB</color>
    <color name="dialog_content_text">#221715</color>

    <color name="dialog_btn_cancel_text">#221715</color>
    <color name="dialog_btn_cancel_stroke">#221715</color>
    <color name="dialog_btn_cancel_stroke_checked">#221715</color>
    <color name="dialog_btn_cancel_bg">#FFFFFF</color>
    <color name="dialog_btn_cancel_bg_checked">#F0F0F0</color>

    <color name="dialog_btn_confirm_text">#221715</color>
    <color name="dialog_btn_confirm_stroke">#221715</color>
    <color name="dialog_btn_confirm_stroke_checked">#221715</color>
    <color name="dialog_btn_confirm_bg">#4996F3</color>
    <color name="dialog_btn_confirm_bg_checked">#4996F3</color>

    <color name="dialog_btn_confirm_text_enable">#80221715</color>
    <color name="dialog_btn_confirm_bg_enable">#384996F3</color>
字符值
    <string name="dialog_title">温馨提示</string>
    <string name="dialog_permission_allow">允许</string>
    <string name="dialog_permission_refuse">拒绝</string>
    <string name="dialog_permission_title">申请权限</string>
    <string name="dialog_btn_cancel">取消</string>
    <string name="dialog_btn_confirm">确认</string>
    <string name="dialog_btn_setting">设置</string>
以前项目中Dialog这里写一个,那边又写一个,所以自己就重构了整个项目的Dialog,先是定义了个简单基类BaseDialog
package com.littlejerk.permissiondemo;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;

import com.blankj.utilcode.util.ActivityUtils;

import androidx.annotation.NonNull;

/**
 * @author : HHotHeart
 * @date : 2021/9/17 12:46
 * @desc : 描述
 */
public class BaseDialog extends Dialog {
    private Context context;


    public BaseDialog(@NonNull Context context) {
        super(context, R.style.DialogTheme);
        this.context = context;
    }


    /**
     * Dialog显示前处理逻辑
     *
     * @param view Dialog内容布局
     */
    public void show(View view) {
        Window window = getWindow();
        if (window == null) return;
        window.setContentView(view);
        WindowManager.LayoutParams pl = window.getAttributes();
        pl.gravity = Gravity.CENTER; //位置
        pl.height = WindowManager.LayoutParams.WRAP_CONTENT;
        int width = window.getDecorView().getResources().getDisplayMetrics().widthPixels;
        pl.width = (int) (width * 0.9);
        window.setAttributes(pl);
        show();
    }

    @Override
    public void show() {
        Activity activity = ActivityUtils.getActivityByContext(context);
        if (activity != null && !activity.isFinishing()) {
            super.show();
        }
    }

    @Override
    public void dismiss() {
        Activity activity = ActivityUtils.getActivityByContext(context);
        if (activity != null && !activity.isFinishing()) {
            super.dismiss();
        }
    }

    /**
     * 是否是外部区域
     *
     * @param context
     * @param event
     * @return
     */
    public boolean isOutOfBounds(Context context, MotionEvent event) {

        final int x = (int) event.getX();
        final int y = (int) event.getY();

        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
        final Window window = getWindow();
        if (window == null) return false;
        final View decorView = getWindow().getDecorView();
        return (x < -slop) || (y < -slop) || (x > (decorView.getWidth() + slop)) || (y > (decorView.getHeight() + slop));
    }
}
然后使用单例模式AppDialogManager来管理Dialog,如下是完整的代码
package com.littlejerk.permissiondemo;


import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.blankj.utilcode.util.SizeUtils;
import com.blankj.utilcode.util.StringUtils;
import com.flyco.roundview.RoundTextView;

/**
 * @author : HHotHeart
 * @date : 2021/8/21 01:03
 * @desc : Dialog公共管理类
 */
public class AppDialogManager {

    private AppDialogManager() {
    }

    public static AppDialogManager getInstance() {
        return Holder.instance;
    }

    private static class Holder {
        private static AppDialogManager instance = new AppDialogManager();
    }

    /**
     * 普通弹框-只有一个实例的弹框
     */
    private BaseDialog mDialog = null;

    /**
     * 扩展的Dialog回调
     */
    public interface DialogClickCallback {
        void onClick(int index);
    }

    /**
     * 权限申请弹框
     *
     * @param activity
     * @param content
     * @param positiveLister
     */
    public void showPermissionRemindDialog(Activity activity, String content,
                                           DialogInterface.OnClickListener negativeLister, DialogInterface.OnClickListener positiveLister) {
        showCommonDialog(activity,
                activity.getString(R.string.dialog_permission_title), content,
                activity.getString(R.string.dialog_permission_refuse), negativeLister,
                activity.getString(R.string.dialog_permission_allow), positiveLister);
    }

    /**
     * 权限设置弹框提示
     *
     * @param activity
     * @param content
     * @param positiveLister
     */
    public void showPermissionSettingRemind(Activity activity, String content,
                                            DialogInterface.OnClickListener negativeLister, DialogInterface.OnClickListener positiveLister) {
        showCommonDialog(activity,
                activity.getString(R.string.dialog_permission_title), content,
                activity.getString(R.string.dialog_btn_cancel), negativeLister,
                activity.getString(R.string.dialog_btn_setting), positiveLister);
    }

    /**
     * 有Positive按钮的Dialog
     *
     * @param activity
     * @param title
     * @param content
     * @param positive
     * @param positiveLister
     */
    public void showPositiveDialog(Activity activity, String title, String content,
                                   String positive, DialogInterface.OnClickListener positiveLister) {
        showCommonDialog(activity, title, content, null, null, positive, positiveLister);
    }

    /**
     * 有确认和取消按钮(没有title)
     *
     * @param activity
     * @param content
     * @param positiveLister
     */
    public void showCommonDialog(Activity activity, String content, DialogInterface.OnClickListener positiveLister) {
        showCommonDialog(activity, null, content,
                activity.getString(R.string.dialog_btn_cancel), null,
                activity.getString(R.string.dialog_btn_confirm), positiveLister);
    }

    /**
     * 公共方法
     *
     * @param activity
     * @param title
     * @param content
     * @param negative
     * @param negativeLister
     * @param positive
     * @param positiveLister
     */
    public void showCommonDialog(Activity activity, String title, String content,
                                 String negative, DialogInterface.OnClickListener negativeLister,
                                 String positive, DialogInterface.OnClickListener positiveLister) {
        showCommonDialog(activity, title, content, negative, negativeLister, positive, positiveLister, true);
    }

    /**
     * 公共方法
     *
     * @param activity
     * @param title
     * @param content
     * @param negative
     * @param negativeLister
     * @param positive
     * @param positiveLister
     * @param isClickDismiss
     */
    public void showCommonDialog(Activity activity, String title, String content,
                                 String negative, DialogInterface.OnClickListener negativeLister,
                                 String positive, DialogInterface.OnClickListener positiveLister, boolean isClickDismiss) {
        showDialog(activity, title, content, negative, negativeLister, positive, positiveLister,
                false, false, null,
                true, isClickDismiss);
    }


    /**
     * Dialog基本方法
     *
     * @param activity                 显示Dialog的Activity
     * @param title                    Dialog 标题
     * @param content                  Dialog 内容
     * @param negative                 左边按钮
     * @param negativeLister           左边按钮的点击事件
     * @param positive                 右边按钮
     * @param positiveLister           右边按钮的点击事件
     * @param isCanceledOnTouchOutside 点击非Dialog内容部分是否允许Dismiss
     * @param isCancelable             点击后退键是否允许Dismiss
     * @param dismissListener          Dialog消失的监听事件
     * @param isMultiDialog            是否允许多个Dialog同时存在
     * @param isClickDismiss           点击按钮是否允许dismiss Dialog
     */
    private void showDialog(Activity activity,
                            String title,
                            String content,
                            String negative, final DialogInterface.OnClickListener negativeLister,
                            String positive, final DialogInterface.OnClickListener positiveLister,
                            boolean isCanceledOnTouchOutside,
                            boolean isCancelable,
                            final DialogInterface.OnDismissListener dismissListener,
                            boolean isMultiDialog,
                            final boolean isClickDismiss) {

        View view = LayoutInflater.from(activity).inflate(R.layout.dialog_common_view, null);
        TextView tvTitle = view.findViewById(R.id.tv_dialog_title);
        TextView tvContent = view.findViewById(R.id.tv_dialog_content);
        tvContent.setMovementMethod(ScrollingMovementMethod.getInstance());
        RoundTextView rtvLeft = view.findViewById(R.id.rtv_left);
        RoundTextView rtvRight = view.findViewById(R.id.rtv_right);
        //显示title逻辑
        if (!StringUtils.isEmpty(title)) {
            tvTitle.setText(title);
            tvTitle.setVisibility(View.VISIBLE);
        } else {
            tvTitle.setVisibility(View.GONE);
        }
        //内容为空时,直接return,不显示dialog
        if (StringUtils.isEmpty(content)) {
            return;
        }
        //显示content逻辑
        tvContent.setText(content);
        tvContent.setVisibility(View.VISIBLE);
        //没有标题时,content的上下距离30dp、文字大小14sp
        if (StringUtils.isEmpty(title)) {
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tvContent.getLayoutParams();
            params.setMargins(
                    SizeUtils.dp2px(15), SizeUtils.dp2px(30),
                    SizeUtils.dp2px(15), SizeUtils.dp2px(30));
            tvContent.setLayoutParams(params);
        }

        //沒有title,只有右边按钮时,content文字大小为12sp
        if (StringUtils.isEmpty(title) && StringUtils.isEmpty(negative) && !StringUtils.isEmpty(positive)) {
            tvContent.setTextSize(12);
        }

        if (!StringUtils.isEmpty(negative)) {
            rtvLeft.setText(negative);
            rtvLeft.setVisibility(View.VISIBLE);
        } else {
            rtvLeft.setVisibility(View.GONE);
        }
        if (!StringUtils.isEmpty(positive)) {
            rtvRight.setText(positive);
            rtvRight.setVisibility(View.VISIBLE);
        } else {
            rtvRight.setVisibility(View.GONE);
        }

        if (isMultiDialog) {
            //允许多个Dialog存在
            final BaseDialog dialog = new BaseDialog(activity);
            //外部是否可以取消
            dialog.setCanceledOnTouchOutside(isCanceledOnTouchOutside);
            //返回是否可以取消
            dialog.setCancelable(isCancelable);

            dialog.setOnDismissListener(dialog1 -> {
                if (dismissListener != null) dismissListener.onDismiss(dialog1);
            });

            rtvLeft.setOnClickListener(v -> {
                if (isClickDismiss) {
                    dialog.dismiss();
                }
                if (negativeLister != null) {
                    negativeLister.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
                }

            });
            rtvRight.setOnClickListener(v -> {
                if (isClickDismiss) {
                    dialog.dismiss();
                }
                if (positiveLister != null) {
                    positiveLister.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
                }

            });
            dialog.show(view);
        } else {
            //只允许一个Dialog存在
            resetLatestDialog(mDialog);
            mDialog = new BaseDialog(activity);
            //外部是否可以取消
            mDialog.setCanceledOnTouchOutside(isCanceledOnTouchOutside);
            //返回是否可以取消
            mDialog.setCancelable(isCancelable);

            mDialog.setOnDismissListener(dialog -> {
                if (dismissListener != null) dismissListener.onDismiss(dialog);
            });

            rtvLeft.setOnClickListener(v -> {
                if (isClickDismiss) {
                    mDialog.dismiss();
                }
                if (negativeLister != null) {
                    negativeLister.onClick(mDialog, DialogInterface.BUTTON_NEGATIVE);
                }

            });
            rtvRight.setOnClickListener(v -> {
                if (isClickDismiss) {
                    mDialog.dismiss();
                }
                if (positiveLister != null) {
                    positiveLister.onClick(mDialog, DialogInterface.BUTTON_POSITIVE);
                }

            });
            mDialog.show(view);
        }

    }

    /**
     * 释放掉最近显示的Dialog
     *
     * @param dialog
     */
    private void resetLatestDialog(Dialog dialog) {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
            dialog = null;
        }
    }

}
这里我们提供了一个最终调用方法,不同样式可通过传入不同参数控制
private void showDialog(Activity activity,
                            String title,
                            String content,
                            String negative, final DialogInterface.OnClickListener negativeLister,
                            String positive, final DialogInterface.OnClickListener positiveLister,
                            boolean isCanceledOnTouchOutside,
                            boolean isCancelable,
                            final DialogInterface.OnDismissListener dismissListener,
                            boolean isMultiDialog,
                            final boolean isClickDismiss);
方法参数和说明如下
activity上下文
title标题
content内容
negative左边按钮(取消)
negativeLister左边按钮的回调
positive右边按钮(确认)
positiveLister右边按钮的回调
isCanceledOnTouchOutside点击非Dialog内容部分是否允许dismiss
isCancelable点击后退键是否允许dismiss
dismissListenerdialog消失的监听事件
isMultiDialog是否允许多个dialog同时存在
isClickDismiss点击按钮是否允许 dismiss dialog

可实现的功能

  • 可任意修改按钮文案
  • 设置是否有标题
  • 控制按钮的数量
  • 按钮点击事件回调
  • 任意控制dialog的消失(如强制更新按钮点击不允许dialog消失、back键等)
要想实现这些功能,直接重载上面这个showDialog()方法。

文章主要讲解了小球项目中dialog的样式管理,我们可以根据代码修改符合自己项目的dialog,如dialog的位置显示、圆角控制、左右边距、按钮的显示样式等等,这里只是提供一个思路,以后应该会整合一些常用的dialog,欢迎大家来支持关注一波。最后,文章代码在 PermissionDemo里,有需要可以去看看!

APP合规检查系列文章:
Android 组件导出风险及防范
Android Activity防劫持方案
Android 申请权限前简单封装弹框阐述申请理由工具类,应付app合规检查
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 08:05:55  更:2021-09-19 08:08:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:40:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码