前言

在日常的android开发中,我们或多或少都有做过应用内的一些弹窗,比如在应用的某些页面弹窗展示广告,弹窗通知消息等。你的app中使用弹窗是否比较频繁?你是否厌烦了每次敲击一大堆代码就为了展示一个弹窗?是否同个页面有多个弹窗且伴有优先级?…等等,那么,可能这篇分享会帮助到你。

使用场景

1. 普通场景

弹窗任务只是展示一些内容,如文本、图片等信息,可能还要有点击事件等,如果对UI要求不是很严格,那么可以使用系统提供的AlertDialog,这里简单写个示范:

AlertDialog.Builder builder = new AlertDialog.Builder(this);AlertDialog alertDialog = builder.setTitle("温馨提示").setMessage("这是弹窗内容").setPositiveButton("知道了", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {ToastUtil.getInstance().show("点击了知道了");}}).create();alertDialog.show();

看下效果

到这里完成了弹窗的展示和关闭,不过弹窗的样式随着系统版本的不同而不同,在低版本上尤其不美观。
多数时候我们还需要根据设计图来实现弹窗,这个时候用系统提供的默认样式就不适用了,需要我们自定义实现弹窗。

2. 自定义弹窗

包括Dialog和PopupWindow,我们可能经常都需要自行定义合适的Dialog或PopupWindow来满足我们的业务场景,当业务场景满足的时候还需要考虑使用的便捷性和简洁性。

  • 这里以PopupWindow为例,来看看我们的不单单是自定义且还需要有通用性的自定义弹窗应该是什么样子的:
new CommonPopupWindow.ViewBuilder<CustomLayout>().width(ConstraintLayout.LayoutParams.MATCH_PARENT).height(ConstraintLayout.LayoutParams.WRAP_CONTENT).outsideTouchable(true).focusable(true).view(new CustomLayout(this)).alpha(0.618f).animationStyle(R.style.pop_animation).intercept(new CommonPopupWindow.ViewEvent<CustomLayout>() {@Overridepublic void getView(CommonPopupWindow popupWindow, CustomLayout view) {/*view表示我们设置的弹窗上的ViewGroup,可在这里做一些初始化操作*/}}).build(context).showAsDropDown(target);

这里不是本文的重点,就不展开说明了,找时间会单独写一篇文章来分享我的自定义弹窗心得。

3. 特殊场景

前面说的都是为了引出本文要将的重点:页面弹窗接入优先级管理。

  • 这里先提出几个问题,如果一个页面需要多个弹窗,弹窗之间的展示有规定的先后顺序,单个弹窗展示有前提条件(如页面处于某个tab)等等跟弹窗相关的一大堆逻辑,这个时候你会怎么处理?也许你会说:我创建多个弹窗,先展示优先级高的弹窗,在该弹窗的onDismissListener回调中展示优先级低的弹窗。
  • 我想说的是,如果页面中的弹窗一两个的时候这么做是可以的,但是如果每个页面中有很多个弹窗呢?比如什么弹窗广告啊,引导提示啊,活动提示啊等等,这个时候如果还是以这种方法去实现优先级的逻辑,那要写的地方就太多了,一不小心还会出错。如果再来个变态的需求,我们这里随便举个例子,比如某个弹窗只能当页面处于某个tab
    下才能展示,是不是又要写一大堆判断?有没有什么办法能解决这个问题,当然有,请往下看。

4. 弹窗优先级管理

这里说的弹窗管理者(以下称DialogManager)对应的弹窗应该是一个抽象的概念,不单指Dialog或PopupWindow,所以我们的DialogManager使用的范围也不受限制,只要遵循约定的interface任何类都可以纳入DialogManager的管理,为了好理解我们将此interface命名为Dialog。
组成DialogManager的除了Dialog(interface)还有DialogParam,下边我们先看看源码:

  1. Dialog
   /*** “窗口”约定规则*/public interface Dialog {/*** 展示*/void show();/*** 关闭** @param isCrowdOut 是否被挤出*/void dismiss(boolean isCrowdOut);/*** 设置“窗口”关闭监听*/void setOnDismissListener(OnDismissListener listener);/*** 设置“窗口”展示监听*/void setOnShowListener(OnShowListener listener);/*** 是否满足show的条件(如处于某个tab,不关心时返回true就行)*/boolean isCanShow();}

其中OnDismissListener 和OnShowListener是我们自定义的,源码如下:

   /*** “窗口”展示监听*/public interface OnShowListener {void onShow();}/*** “窗口”关闭监听*/public interface OnDismissListener {/*** @param isCrowdOut 是否被挤出*/void onDismiss(boolean isCrowdOut);}
  1. DialogParam
   /*** 窗口参数类*/public static class DialogParam {/*** “窗口”*/private Dialog dialog;/*** 优先级,值越大优先级越高*/private int priority;/*** 当前是否处于show状态*/private boolean isShowing;/*** 是否准备show(在show之后非用户自己手动关掉弹窗(调dismiss或触摸弹窗外部)* 接着show了一个优先级更高的Dialog,当该Dialog dismiss后可自动show剩下的* 优先级最高的Dialog* )*/private boolean prepareShow;private DialogParam(Builder builder) {dialog = builder.dialog;priority = builder.priority;prepareShow = builder.prepareShow;}public Dialog getDialog() {return dialog;}public void setDialog(Dialog dialog) {this.dialog = dialog;}public int getPriority() {return priority;}public void setPriority(int priority) {this.priority = priority;}public boolean isShowing() {return isShowing;}public void setShowing(boolean showing) {isShowing = showing;}public boolean isPrepareShow() {return prepareShow;}public void setPrepareShow(boolean prepareShow) {this.prepareShow = prepareShow;}public static class Builder {/*** “窗口”*/private Dialog dialog;/*** 优先级,值越大优先级越高*/private int priority;/*** 是否准备show(在show之后非用户自己手动关掉弹窗(调dismiss或触摸弹窗外部)* 接着show了一个优先级更高的Dialog,当该Dialog dismiss后可自动show剩下的* 优先级最高的Dialog* )*/private boolean prepareShow = true;public Builder dialog(Dialog dialog) {this.dialog = dialog;return this;}public Builder priority(int priority) {this.priority = priority;return this;}public Builder prepareShow(boolean prepareShow) {this.prepareShow = prepareShow;return this;}public DialogParam build() {return new DialogParam(this);}}}
  1. DialogManager
import android.text.TextUtils;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 作者:lpx on 2020/8/24 17:39* Email : 1966353889@qq.com* Describe:弹窗管理(支持设置弹窗优先级)* update on 2020/8/26 16:49*/
public class DialogManager {private List<DialogParam> mDialogs;private static DialogManager mDefaultInstance;private DialogManager() {}/*** 获取弹窗管理者*/public static DialogManager getInstance() {if (mDefaultInstance == null) {synchronized (DialogManager.class) {if (mDefaultInstance == null) {mDefaultInstance = new DialogManager();}}}return mDefaultInstance;}/*** 添加弹窗** @param dialogParam 待添加的弹窗*/public synchronized void add(DialogParam dialogParam) {if (dialogParam != null && dialogParam.getDialog() != null) {if (mDialogs == null) {mDialogs = new ArrayList<>();}dialogParam.getDialog().setOnShowListener(new OnShowListener() {@Overridepublic void onShow() {dialogParam.setShowing(true);dialogParam.setPrepareShow(false);}});dialogParam.getDialog().setOnDismissListener(new OnDismissListener() {@Overridepublic void onDismiss(boolean isCrowdOut) {dialogParam.setShowing(false);if (isCrowdOut) {dialogParam.setPrepareShow(true);} else {mDialogs.remove(dialogParam);showNext();}}});mDialogs.add(dialogParam);}}/*** 展示弹窗** @param dialogParam 待展示的弹窗*/public synchronized void show(DialogParam dialogParam) {if (dialogParam != null && dialogParam.getDialog() != null) {if (mDialogs == null) {if (dialogParam.getDialog().isCanShow()) {dialogParam.getDialog().show();}} else {/*判断优先级及是否可展示*/maybeShow(dialogParam);}}}/*** 展示弹窗(优先级最高的Dialog)*/public synchronized void show() {DialogParam dialogParam = getMaxPriorityDialog();if (dialogParam != null) {Dialog dialog = dialogParam.getDialog();if (dialog != null && dialog.isCanShow()) {dialog.show();}}}/*** 清除弹窗管理者*/public synchronized void clear() {if (mDialogs != null) {for (int i = 0, size = mDialogs.size(); i < size; i++) {if (mDialogs.get(i) != null) {mDialogs.get(i).setPrepareShow(false);}}for (int i = 0, size = mDialogs.size(); i < size; i++) {if (mDialogs.get(i) != null) {Dialog dialog = mDialogs.get(i).getDialog();if (dialog != null) {dialog.dismiss(false);}}}mDialogs.clear();}}/*** 清除弹窗管理者** @param dismiss 是否同时dismiss掉弹窗管理者维护的弹窗*/public synchronized void clear(boolean dismiss) {if (mDialogs != null) {for (int i = 0, size = mDialogs.size(); i < size; i++) {if (mDialogs.get(i) != null) {mDialogs.get(i).setPrepareShow(false);}}if (dismiss) {for (int i = 0, size = mDialogs.size(); i < size; i++) {if (mDialogs.get(i) != null) {Dialog dialog = mDialogs.get(i).getDialog();if (dialog != null) {dialog.dismiss(false);}}}}mDialogs.clear();}}/*** 展示下一个优先级最大的Dialog(非自行调用dismiss而是被优先级高的弹窗show后挤掉)*/private synchronized void showNext() {DialogParam dialog = getMaxPriorityDialog();if (dialog != null) {if (dialog.isPrepareShow() && dialog.getDialog().isCanShow()) {dialog.getDialog().show();}}}/*** 展示弹窗(满足条件可展示)** @param dialogParam 待展示的弹窗*/private void maybeShow(DialogParam dialogParam) {if (dialogParam != null && dialogParam.getDialog() != null) {DialogParam topShowDialog = getShowingDialog();if (topShowDialog == null) {if (dialogParam.getDialog().isCanShow()) {dialogParam.getDialog().show();}} else {/*获取优先级*/int priority = dialogParam.getPriority();if (priority >= topShowDialog.getPriority()) {if (dialogParam.getDialog().isCanShow()) {dialogParam.getDialog().show();topShowDialog.getDialog().dismiss(true);/*设置参数支持当前show关闭后自动show带该参数的优先级最高的弹窗*/topShowDialog.setPrepareShow(true);}}}}}/*** 获取当前栈中优先级最高的Dialog(优先级相同则返回后添加的弹窗)*/private synchronized DialogParam getMaxPriorityDialog() {if (mDialogs != null) {int maxPriority = -1;int position = -1;for (int i = 0, size = mDialogs.size(); i < size; i++) {DialogParam dialog = mDialogs.get(i);if (i == 0) {position = 0;maxPriority = dialog.getPriority();} else {if (dialog.getPriority() >= maxPriority) {position = i;maxPriority = dialog.getPriority();}}}if (position != -1) {return mDialogs.get(position);} else {return null;}}return null;}/*** 获取当前处于show状态的弹窗*/private synchronized DialogParam getShowingDialog() {if (mDialogs != null) {for (int i = 0, size = mDialogs.size(); i < size; i++) {DialogParam dialogParam = mDialogs.get(i);if (dialogParam != null && dialogParam.getDialog() != null && dialogParam.isShowing()) {return dialogParam;}}}return null;}}

使用方法

  1. 自定义弹窗类实现Dialog(Interface)
    这里还是以AlertDialog的自定义为例
import android.content.Context;
import android.content.DialogInterface;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;/*** 作者:lpx on 2020/8/27 11:47* Email : 1966353889@qq.com* Describe:窗口例子类*/
public class DialogSample extends AlertDialog implements Dialog {/*** 是否被挤出(每个实现DialogManager.Dialog的窗口类都需要新建该变量)*/private boolean isCrowdOut;protected DialogSample(@NonNull Context context) {super(context);}protected DialogSample(@NonNull Context context, int themeResId) {super(context, themeResId);}protected DialogSample(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {super(context, cancelable, cancelListener);}@Overridepublic void show() {super.show();}@Overridepublic void dismiss(boolean isCrowdOut) {/*isCrowdOut在super.dismiss()之前赋值*/this.isCrowdOut = isCrowdOut;super.dismiss();}@Overridepublic void setOnDismissListener(DialogManager.OnDismissListener listener) {setOnDismissListener(new OnDismissListener() {@Overridepublic void onDismiss(DialogInterface dialog) {listener.onDismiss(isCrowdOut);}});}@Overridepublic void setOnShowListener(DialogManager.OnShowListener listener) {setOnShowListener(new OnShowListener() {@Overridepublic void onShow(DialogInterface dialog) {listener.onShow();}});}/*** 每个实现DialogManager.Dialog的窗口类都需要实现该* 方法告诉DialogManager是否可展示此窗口(比如有些窗* 口只在页面的某个tab下才能展示)*/@Overridepublic boolean isCanShow() {return true;}
}
  1. 添加到DialogManager
    在对应的页面添加自定义弹窗并纳入优先级管理
        DialogSample alertDialog1;DialogSample alertDialog2;DialogSample alertDialog3;int[] prioritys = new int[]{3, 1, 2};alertDialog1 = new DialogSample2(context);alertDialog1.setTitle("温馨提示");alertDialog1.setMessage("第一个弹窗,优先级:" + prioritys[0]);alertDialog1.setCancelable(false);alertDialog1.setButton(DialogInterface.BUTTON_POSITIVE, "关闭", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {/*调用此方法传false告诉DialogManager此窗口dismiss是用户自己关闭的,而非被优先级更高的弹窗show后被挤出,这种情况优先级更高的弹窗dismiss后DialogManager不会重新show此弹窗*/alertDialog1.dismiss(false);}});alertDialog2 = new DialogSample2(context);alertDialog2.setTitle("温馨提示");alertDialog2.setMessage("第二个弹窗,优先级:" + prioritys[1]);alertDialog2.setCancelable(false);alertDialog2.setButton(DialogInterface.BUTTON_POSITIVE, "关闭", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {/*调用此方法传false告诉DialogManager此窗口dismiss是用户自己关闭的,而非被优先级更高的弹窗show后被挤出,这种情况优先级更高的弹窗dismiss后DialogManager不会重新show此弹窗*/alertDialog2.dismiss(false);}});alertDialog3 = new DialogSample2(context);alertDialog3.setTitle("温馨提示");alertDialog3.setMessage("第三个弹窗,优先级:" + prioritys[2]);alertDialog3.setCancelable(false);alertDialog3.setButton(DialogInterface.BUTTON_POSITIVE, "关闭", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {/*调用此方法传false告诉DialogManager此窗口dismiss是用户自己关闭的,而非被优先级更高的弹窗show后被挤出,这种情况优先级更高的弹窗dismiss后DialogManager不会重新show此弹窗*/alertDialog3.dismiss(false);}});DialogManager.getInstance().add(new DialogParam.Builder().dialog(alertDialog1).priority(prioritys[0]).build());DialogManager.getInstance().add(new DialogParam.Builder().dialog(alertDialog2).priority(prioritys[1]).build());DialogManager.getInstance().add(new DialogParam.Builder().dialog(alertDialog3).priority(prioritys[2]).build());

在需要展示弹窗时调:

DialogManager.getInstance().show();

效果图如下:

结尾

是不是很方便快捷,希望本文可以帮助到您,也希望各位不吝赐教,提出您在使用中的宝贵意见,谢谢。
如果可以的话,也可以扫一扫下方的二维码请作者喝一杯奶茶哈

谢谢您的观看。
有问题可发送至:1966353889@qq.com
欢迎交流,共同进步。

Android优雅实现弹窗优先级管理相关推荐

  1. Android系统中的进程管理:进程的优先级

    本文是Android进程管理系列文章的第二篇,会讲解进程管理中的优先级管理. 进程管理的第一篇文章:<进程的创建>请跳转至这里. 本文适合Android平台的应用程序开发者,也适合对于An ...

  2. Android系统中的进程管理:内存的回收

    本文是Android系统进程管理的第三篇文章.进程管理的前面两篇文章,请参见这里: Android系统中的进程管理:进程的创建 Android系统中的进程管理:进程的优先级 本文适合Android平台 ...

  3. Android系统中的进程管理:进程的创建

    对于操作系统来说,进程管理是其最重要的职责之一. 考虑到这部分的内容较多,因此会拆分成几篇文章来讲解. 本文是进程管理系统文章的第一篇,会讲解Android系统中的进程创建. 本文适合Android平 ...

  4. 如何优雅地进行接口管理?(大厂内部分享)

    时间都去哪里了 敏捷迭代和团队协作,前后端分离的工作模式几乎是每个互联网公司的常规工作模式. 前后端分离,各自开发的优点很多,其中一项是它只需要提供一个统一的API接口,即可被web,iOS,Andr ...

  5. 第十一篇 ANDROID 系统网络连接和管理机制与架构

    一  网络连接功能介绍 ANDROID 系统网络连接和管理服务由四个系统服务ConnectivityService.NetworkPolicyManagerService.NetworkManagem ...

  6. android中进程的优先级

    android中进程的优先级 转载于:https://www.cnblogs.com/Renyi-Fan/p/7472027.html

  7. Gradle for Android 第三篇( 依赖管理 )

    Gradle for Android 第三篇( 依赖管理 ) 依赖管理是Gradle最闪耀的地方,最好的情景是,你仅仅只需添加一行代码在你的build文件,Gradle会自动从远程仓库为你下载相关的j ...

  8. Android官方文章翻译之管理设备苏醒状态(Managing Device Awake State)(二)

    这是Managing Device Awake State的下半篇,上半篇请看:Android官方文章翻译之管理设备苏醒状态(Managing Device Awake State)(一) 在了解接下 ...

  9. android sdk是灰的,Android Studio 2.3 sdk管理器标签灰显

    Android Studio 2.3 - >配置 - > SDK管理器. 这些选项卡呈灰色显示: SDK工具,SDK更新站点.此外,"Show Package Details&q ...

最新文章

  1. 句号一定要划在句子最美的地方
  2. (转)命令行下,用 xcodebuild 生成ipa文件,通过 itms-services 协议安装
  3. houdini帮助文档_用houdini做个简单版本的pcopen
  4. 用计算机做表格的超链接,excel表格中超链接的使用怎么设置
  5. Spring boot的第一个demo
  6. JS之Boolean的valueOf方法
  7. ubuntu-12.04.2忘记管理员密码(图解)
  8. OSPF 224.0.0.5(AllSPFRouters)和224.0.0.6(AllDRouters)的区别
  9. RedHat 7配置keepalived+LVS实现高可用的Web负载均衡
  10. 使用EasyUI加载树形菜单
  11. CDMA2000中的Walsh码,PN码,短码序列的初相位偏置(PN OFFSET)之間的差別與關係(1)
  12. 【计算机网络】HTTP 协议详解
  13. View的事件分发机制
  14. Unity太空大战游戏-Socket网络通信教学示例
  15. 智能合约节省GAS的小技巧:避免使用>=和<=
  16. Seurat SingleCellExperiment anndata相互转化
  17. 2018高中计算机学考,关于2018—2019学年普通高中学业水平考试科目考试时间安排的通知...
  18. 基础算法:斐波那契函数学习
  19. CAD制图软件中如何设置选择对象的显示效果?
  20. 第十一讲 项目3 买五赠一 买二十赠五 优惠计算

热门文章

  1. 在微信小程序中渲染HTML内容
  2. 环保管家——全面排查、智能诊断、贴身帮扶
  3. 【Python】面向对象版学生管理系统(文末有源代码)
  4. 银行软件测试年终总结,银行科技部年终工作总结
  5. 【xlwings api语言参考】Range.AutoFit 方法
  6. 使用ubuntu desktop是可能会用到的配置
  7. Python第四次作业-----宋舒婷
  8. 我的python学习之路_我的Python入门之路
  9. oracle 9i hwm,Oracle中的Low HWM与 High HWM 高水位
  10. Com、Com+\DCom定义和差别