Android 如何实现弹窗顺序&优先级控制
一般在项目首页中,往往会有多个对话框需要弹出,比如活动弹窗、更新弹窗、评分弹窗等等,而且这些弹窗是有优先级顺序的。这些弹窗一般是通过接口请求后返回结果再显示的,如果只有几个弹窗还好处理,业务逻辑上判断一下先后显示就可以。如果有十几个或者更多,那么处理起来将非常麻烦,而且容易出现问题。
所以封装一个可以按照优先级顺序显示的弹窗功能就非常有必要,首先功能需求如下:
- 按优先级顺序阻塞式显示各种类型弹窗,默认从最高优先级开始显示
- 只有上一个高优先级弹窗显示完或者取消显示,下一个低优先级弹窗才可以显示
- 指定显示某一个弹窗的前提是没有更高优先级的弹窗需要显示
- 在显示一个弹窗之前需要判断是否能够或者需要显示
- 根据优先级去查找指定的弹窗,优先级相当于唯一ID
- 弹窗包括多种类型,Dialog、PopupWindow、Activity等等
接着开始编码去实现功能,先定一个枚举类,罗列出支持的弹窗类型,包括Dialog、PopupWindow、Activity等等。
public enum WindowType { DIALOG, POUPOWINDOW, TOAST, SNACKBAR, WIDGET, ACTIVITY, OTHERS }
然后定义弹窗接口IWindow,它定义了弹窗的基本功能。
/** * 窗口约定规则 */ public interface IWindow { /** * 弹窗展示 */ void show(Activity activity); /** * 弹窗关闭 */ void dismiss(); /** * 设置窗口关闭监听 */ void setOnWindowDismissListener(OnWindowDismissListener listener); /** * 设置窗口展示监听 */ void setOnWindowShowListener(OnWindowShowListener listener); }
以及弹窗显示和关闭的监听接口,
/** * 窗口关闭监听 */ public interface OnWindowDismissListener { /** * */ void onDismiss(); } /** * 窗口展示监听 */ public interface OnWindowShowListener { void onShow(); }
接下来定义个包裹类WindowWrapper去封装弹窗相关的属性和状态,包括弹窗、优先级、能否显示、窗体类型等等,在处理弹窗显示逻辑时将会用到。
/** * 窗口参数类 */ public class WindowWrapper { /** * 窗口 */ private IWindow mWindow; /** * 优先级,值越大优先级越高 */ private int mPriority; /** * 当前是否处于show状态 */ private boolean isShowing; /** * 是否满足show的条件 */ private boolean isCanShow; /** * 弹窗类型 */ private WindowType mWindowType; /** * 弹窗名称 */ private String mWindowName; private WindowWrapper(Builder builder) { mWindow = builder.window; mPriority = builder.priority; mWindowType = builder.windowType; isCanShow = builder.isCanShow; mWindowName = builder.windowName; } public IWindow getWindow() { return mWindow; } public void setWindow(IWindow window) { this.mWindow = window; } public int getPriority() { return mPriority; } public void setPriority(int priority) { this.mPriority = priority; } public boolean isShowing() { return isShowing; } public void setShowing(boolean showing) { isShowing = showing; } public WindowType getWindowType() { return mWindowType; } public void setWindowType(WindowType mWindowType) { this.mWindowType = mWindowType; } public boolean isCanShow() { return isCanShow; } public void setCanShow(boolean canShow) { isCanShow = canShow; } public String getWindowName() { return mWindowName; } public void setWindowName(String mWindowName) { this.mWindowName = mWindowName; } public static class Builder { /** * 窗口 */ private IWindow window; /** * 优先级,值越大优先级越高 */ private int priority; /** * 弹窗类型 */ private WindowType windowType; /** * 是否满足show的条件 */ private boolean isCanShow; /** * 弹窗名称 */ private String windowName; public Builder window(IWindow window) { this.window = window; return this; } public Builder priority(int priority) { this.priority = priority; return this; } public Builder windowType(WindowType type) { this.windowType = type; return this; } public Builder setCanShow(boolean canShow) { isCanShow = canShow; return this; } public String getWindowName() { return windowName; } public Builder setWindowName(String windowName) { this.windowName = windowName; return this; } public WindowWrapper build() { return new WindowWrapper(this); } } }
最后通过WindowTaskManager类去统一组织管理弹窗的添加、显示、关闭等逻辑,
public class WindowTaskManager { private List<WindowWrapper> mWindows; private static WindowTaskManager mDefaultInstance; private WindowTaskManager() { } /** * 获取弹窗管理者 */ public static WindowTaskManager getInstance() { if (mDefaultInstance == null) { synchronized (WindowTaskManager.class) { if (mDefaultInstance == null) { mDefaultInstance = new WindowTaskManager(); } } } return mDefaultInstance; } /** * 添加弹窗 * * @param windowWrapper 待显示的弹窗 */ public synchronized void addWindow(Activity activity, WindowWrapper windowWrapper) { if (windowWrapper != null) { if (mWindows == null) { mWindows = new ArrayList<>(); } if (windowWrapper.getWindow() != null) { windowWrapper.getWindow().setOnWindowShowListener(new OnWindowShowListener() { @Override public void onShow() { windowWrapper.setShowing(true); } }); windowWrapper.getWindow().setOnWindowDismissListener(new OnWindowDismissListener() { @Override public void onDismiss() { windowWrapper.setShowing(false); mWindows.remove(windowWrapper); showNext(activity); } }); } mWindows.add(windowWrapper); } } /** * 弹窗满足展示条件 * * @param priority */ public synchronized void enableWindow(Activity activity, int priority, IWindow window) { WindowWrapper windowWrapper = getTargetWindow(priority); if (windowWrapper != null) { if (windowWrapper.getWindow() == null) { window.setOnWindowShowListener(new OnWindowShowListener() { @Override public void onShow() { windowWrapper.setShowing(true); } }); window.setOnWindowDismissListener(new OnWindowDismissListener() { @Override public void onDismiss() { windowWrapper.setShowing(false); mWindows.remove(windowWrapper); showNext(activity); } }); } windowWrapper.setCanShow(true); windowWrapper.setWindow(window); show(activity, priority); } } /** * 移除不需要显示弹窗 * * @param priority */ public synchronized void disableWindow(int priority) { WindowWrapper windowWrapper = getTargetWindow(priority); if (windowWrapper != null && windowWrapper.getWindow() != null) { if (mWindows != null) { mWindows.remove(windowWrapper); } } } /** * 展示弹窗 * 从优先级最高的Window开始显示 */ public synchronized void show(Activity activity) { WindowWrapper windowWrapper = getMaxPriorityWindow(); if (windowWrapper != null && windowWrapper.isCanShow()) { IWindow window = windowWrapper.getWindow(); if (window != null) { window.show(activity); } } } /** * 显示指定的弹窗 * * @param priorities */ public synchronized void show(Activity activity, int priorities) { WindowWrapper windowWrapper = getTargetWindow(priorities); if (windowWrapper != null && windowWrapper.getWindow() != null) { WindowWrapper topShowWindow = getShowingWindow(); if (topShowWindow == null) { int priority = windowWrapper.getPriority(); WindowWrapper maxPriorityWindow = getMaxPriorityWindow(); if (maxPriorityWindow != null && windowWrapper.isCanShow() && priority >= maxPriorityWindow.getPriority()) { if (windowWrapper.getWindow() != null) { windowWrapper.getWindow().show(activity); } } } } } /** * 清除弹窗管理者 */ public synchronized void clear() { if (mWindows != null) { for (int i = 0, size = mWindows.size(); i < size; i++) { if (mWindows.get(i) != null) { IWindow window = mWindows.get(i).getWindow(); if (window != null) { window.dismiss(); } } } mWindows.clear(); } WindowHelper.getInstance().onDestroy(); } /** * 清除弹窗管理者 * * @param dismiss 是否同时dismiss掉弹窗管理者维护的弹窗 */ public synchronized void clear(boolean dismiss) { if (mWindows != null) { if (dismiss) { for (int i = 0, size = mWindows.size(); i < size; i++) { if (mWindows.get(i) != null) { IWindow window = mWindows.get(i).getWindow(); if (window != null) { window.dismiss(); } } } } mWindows.clear(); } WindowHelper.getInstance().onDestroy(); } /** * 展示下一个优先级最大的Window */ private synchronized void showNext(Activity activity) { WindowWrapper windowWrapper = getMaxPriorityWindow(); if (windowWrapper != null && windowWrapper.isCanShow()) { if (windowWrapper.getWindow() != null) { windowWrapper.getWindow().show(activity); } } } /** * 获取当前栈中优先级最高的Window(优先级相同则返回后添加的弹窗) */ private synchronized WindowWrapper getMaxPriorityWindow() { if (mWindows != null) { int maxPriority = -1; int position = -1; for (int i = 0, size = mWindows.size(); i < size; i++) { WindowWrapper windowWrapper = mWindows.get(i); if (i == 0) { position = 0; maxPriority = windowWrapper.getPriority(); } else { if (windowWrapper.getPriority() >= maxPriority) { position = i; maxPriority = windowWrapper.getPriority(); } } } if (position != -1) { return mWindows.get(position); } else { return null; } } return null; } private synchronized WindowWrapper getTargetWindow(int priority) { if (mWindows != null) { for (int i = 0, size = mWindows.size(); i < size; i++) { WindowWrapper windowWrapper = mWindows.get(i); if (windowWrapper != null && windowWrapper.getPriority() == priority) { return windowWrapper; } } } return null; } /** * 获取当前处于show状态的弹窗 */ private synchronized WindowWrapper getShowingWindow() { if (mWindows != null) { for (int i = 0, size = mWindows.size(); i < size; i++) { WindowWrapper windowWrapper = mWindows.get(i); if (windowWrapper != null && windowWrapper.getWindow() != null && windowWrapper.isShowing()) { return windowWrapper; } } } return null; } }
WindowTaskManager类有三个主要方法:
- addWindow(Activity activity, WindowWrapper windowWrapper)
- enableWindow(Activity activity, int priority, IWindow window)
- disableWindow(int priority)
需要按顺序显示的对话框统一使用addWindow方法添加,这是还未进行网络请求之前就要调用的。作用是告诉WindowTaskManager一共有多少个弹窗需要按顺序显示。当网络请求返回之后,如果需要显示弹窗就调用enableWindow方法去显示,如果不需要显示弹窗就调用disableWindow方法,将这个弹窗从显示队列中移除。
以上就是按顺序显示弹窗的主要逻辑,使用的话窗体先继承IWindow,实现相关方法。然后通过操作WindowTaskManager类就可以了。具体使用方法参见源码。
彩蛋:
需要在DialogFragment中显示DialogFragment时候,最好不要直接在DialogFragment启动显示,而是在DialogFragment的消失回调中启动显示。因为当前一个DialogFragment消失的时候,getChildFragmentManager可能会失效,应该在外层使用getFragmentManager。
以上就是Android 如何实现弹窗顺序&优先级控制的详细内容,更多关于Android 实现弹窗顺序和优先级控制的资料请关注我们其它相关文章!