背景

在快速开发的背景下,经历了n个版本后的Android App中已经存在了各种各样看似相同却各有差别的弹框样式。其中包括系统弹框和自定义弹框,并且在线上时常会出现IllegalArgumentException的异常,而现有的解决方法是通过工具类来保护调用show和dismiss方法,这种方式效率不高,而且覆盖不全,开发过程中容易遗漏。另外现有的Builder方式的弹框构造工具虽然功能强大,能构造各种弹框,但是使用复杂,样式逻辑耦合,使用成本太高。于是,便需要一款样式统一、show和dismiss安全、调用简单、构造方便的统一弹框工具。

目标

1.统一弹框的交互样式
2.show和dismiss方法安全
3.样式与逻辑解耦,使用者不必关心弹框样式,只需要完成自己的续逻辑即可
4.使用简单,一个接口即可获得所需样式
5.扩展性,可支持展示特别样式弹框

怎么做?

既然有了特定的目标,那么就要开始弹框的设计了。弹框通过工厂模式设计生产,使用者通过CommonDialogFactory提供的接口,可以直接生产CommonDialog类、KaolaCommonDialog类、KaolaBottomCloseDialog类三种弹框,其中CommonDialog是为了兼容旧逻辑保留的旧的弹框样式,KaolaCommonDialog是新设计统一了样式的弹框类,但是两者在样式上没有很大的区别,KaolaBottomCloseDialog是一种底部关闭的弹框样式。

0. 保留CommonDialog的旧的构建方式。

考虑到旧的弹框中有不少弹框的业务逻辑与旧的Builder工具样式有耦合,为了保证业务逻辑不受影响,我保留了以前的Builder方式构造弹框的设计,并且对其进行了接口化封装。这样可以降低构造弹框的成本。

1. 整理目前项目中用到的弹框的样式。

由于不熟悉别的模块中弹框到底有哪些样式,所以需要整理目前项目中所有用到的弹框样式。统计结果发现大部分弹框使用的是系统弹框,而自定义弹框中不少样式已经不再使用,但是在旧的构造工具中依然存在,由于逻辑耦合,后期维护相对麻烦,这也验证了我们统一弹框组件的必要性。

2. 慢慢从DialogManager里面把样式抽出来,形成基本样式。

从旧的弹框管理类DialogManager中,将现在正在使用的弹框抽离出来,在弹框工厂CommonDialogFactory中封装成单独的接口以提供使用。也可以根据整理的接口,形成一套基本的弹框样式,这样在后面做样式统一的时候就可以参考着现有的样式去做了。

3. 具体弹框样式形成文档维护在wiki上(提供使用帮助)。

那么为了更方便地使用和维护统一弹框组件,使用文档是必不可少的。把现有的弹框样式总结在wiki文档中,对于现有可用的弹框样式也是一目了然;还可以根据文档中提供的案例进行调用开发,降低成本。

4. 样式全部抽出来之后,那就按照统一的交互进行修正。

由于目前没有视觉提供的统一样式,所以我们基于第2点钟抽离出来的基本样式,按照这些样式来做构建的统一。然后再按照后续设计提供的统一交互规范进行进一步的修正,慢慢做到样式也统一,最后真正实现弹框的完全统一。

样式

下图中可以看到弹框类的继承关系:

KaolaBaseDialog中实现了安全的show和dismiss方法:

@Overridepublic void show() {   if (!checkAllow()) {        return;}   // 防止check无效try {        super.show();} catch (Exception e) {e.printStackTrace();}
}

@Overridepublic void dismiss() {   if (mOnDismissListener != null) {mOnDismissListener.onDismiss(mDismissType);}    if (!checkAllow()) {        return;}    try {        super.dismiss();} catch (Exception e) {e.printStackTrace();}
}/**
* 检查环境是否允许
*
* @return
*/private boolean checkAllow() {Context context = this.getContext();    if (context instanceof Lifeful) {Lifeful lifeful = (Lifeful) context;        if (!lifeful.isAlive()) {            return false;}} else if (context instanceof Activity) {        if (!ActivityUtils.activityIsAlive(context)) {            return false;}}    return true;
}

KaolaCommonDialog是通用样式类:

KaolaBottomDialog是底部弹出浮层:

KaolaBottomConfirmDialog是底部确认浮层:

KaolaBottomCloseDialog是底部带关闭弹框:

ExpectPickUpTimeDialog是时间选择器浮层:

通用弹框的文案也支持SpannableString的多样展示;另外可以看到KaolaBaseDialog可以使用在各种情况下,不仅仅是通用弹框,还可以是一些通用组件比如ExpectPickUpTimeDialog时间选择器(不过这里做成了与取件业务相关的组件)。

怎么用?

KaolaCommonDialog的使用

直接调用CommonDialogFactory提供的createOneOrTwoButtonsCustomView接口,该接口可以提供标题、文案、自定义view、通用按钮的展示,使用者可以通过wiki文档或者直接查看接口注释了解接口内容。

/**
* 一个标题,一个文案,一个view,一个白底红字negative(left)按钮,一个红底白字positive(right)按钮
*
* @param context
* @param title 标题,传空不带标题
* @param message 提示文案
* @param view 自定义区域需要添加的view
* @param leftBtn 左边按钮的内容(传空不显示按钮)
* @param rightBtn 右边按钮的内容(传空不显示按钮)
* @return KaolaCommonDialog
*/public KaolaCommonDialog createOneOrTwoButtonsWithCustomView(Context context, String title, CharSequence message,View view, String leftBtn, String rightBtn) {...}

KaolaCommonDialog dialog = CommonDialogFactory.getInstance().createOneOrTwoButtonsWithCustomView(this, "标题", "提示文案", getCustomView(), "取消", "确定").setOnLeftButtonClickListener(() -> ToastUtils.show("leftClick... negative")).setOnRightButtonClickListener(() -> ToastUtils.show("rightClick... positive")).setCancelableOutside(true);
dialog.setOnDialogDismissListener(dismissType -> {    // dismiss回调ThreadCore.getInstance().postOnMainLooper(new LifefulRunnable(new Runnable() {        @Overridepublic void run() {            if (dismissType == KaolaBaseDialog.DISMISS_TYPE_POSITIVE) {ToastUtils.show("右侧按钮点击消失");} else if (dismissType == KaolaBaseDialog.DISMISS_TYPE_NEGATIVE) {ToastUtils.show("左侧按钮点击消失");} else {ToastUtils.show("其他消失");}}}, DialogTestActivity.this), 1000);
});// 不展示顶部分割线dialog.dividerTop.setVisibility(View.GONE);
dialog.show();

考虑到一些特殊情况的需求,默认的样式无法满足视觉要求的时候,就需要定制化一些弹框中的内容了。所以弹框类中的各个成员以public的形式开发给使用者,以适应各种定制化要求,比如:不希望展示title下面的分割线,可以直接获取dividerTop对象进行设置。另外自定义view参数可以满足对弹框内容的特殊化定制。在统一了弹框调用之后,依然具有很强的扩展性。

KaolaBottomDialog的使用

考虑到底部浮层的多样性,没有将KaolaBottomDialog的构建放入CommonDialogFactory中,而是使用通用的构建方式构建。

private KaolaBottomDialog chooseDialog;
...
chooseDialog = new KaolaBottomDialog(this);// 展示浮层右上角关闭按钮chooseDialog.showRightClose(true);
...// 设置标题(String)和内容(ListView)chooseDialog.setContent(getString(R.string.refund_delivery), dialogListView)            // 限制浮层最大屏高比(最大为屏幕高度的2/3).setDialogHeight(2f / 3);
chooseDialog.show();

思考

统一交互既能够给产品带来更好体验,又可以减少开发者不必要的开发工作,降低代码耦合,提高工作效率,是一个建议并值得去做的事情。目前的统一弹框方案还是有很多不足,等着我们去优化,比如将所有Dialog统一到CommonDialogFactory中去构建,再使用等等。

原文发布时间为:2018-12-04

本文作者:钱成杰

本文来自云栖社区合作伙伴“终端研发部”,了解相关信息可以关注“终端研发部”。

考拉Android统一弹框相关推荐

  1. 非静默授权没有弹出弹框_网易考拉Android统一弹框

    作者:钱成杰 链接:https://blog.csdn.net/jessicaiu/article/details/82739334 背景 在快速开发的背景下,经历了n个版本后的考拉Android A ...

  2. 如何实现接口统一入口_网易考拉Android App如何实现统一弹框

    摘要 在快速开发的背景下,经历了n个版本后的考拉Android App中已经存在了各种各样看似相同却各有差别的弹框样式.其中包括系统弹框和自定义弹框,并且在线上时常会出现IllegalArgument ...

  3. 网易考拉Android客户端路由总线设计

    1.前言 当前,Android路由框架已经有很多了,如雨后春笋般出现,大概是因为去年提出了Android组件化的概念.当一个产品的业务规模上升到一定程度,或者是跨团队开发时,团队/模块间的合作问题就会 ...

  4. 网易考拉Android客户端网络模块设计

    本文来自网易云社区 作者:王鲁才 客户端开发中不可避免的需要接触到访问网络的需求,如何把访问网络模块设计的更具有扩展性是每一个移动开发者不得不面对的事情.现在有很多主流的网络请求处理框架,如Squar ...

  5. 网易考拉Android客户端路由总线设计 1

    1.前言 当前,Android路由框架已经有很多了,如雨后春笋般出现,大概是因为去年提出了Android组件化的概念.当一个产品的业务规模上升到一定程度,或者是跨团队开发时,团队/模块间的合作问题就会 ...

  6. java路由总线_网易考拉Android客户端路由总线设计

    1.前言 $ e7 |  ~% L) i7 @7 B& t3 T5 h* P/ e2 s 当前,Android路由框架已经有很多了,如雨后春笋般出现,大概是因为去年提出了Android组件化的 ...

  7. android 底部弹框 BottomSheetDialog 的使用

    先简单的说下普通弹框使用 步骤 首先项目需要添加design 库 简单的使用和dialog 一样 如下 BottomSheetDialog sheelt = new BottomSheetDialog ...

  8. Android 自定义 弹框日期选择器 弹框,年月日,时分,

    之前有个项目要用到 日期选择器,于是百度了有关 方法,自己 将其 封装成了 自定义 控件 项目 地址:点击打开链接 效果图 Android 自带 的 日期选择器和时间选择器 为DatePicker 和 ...

  9. android自动化测试弹框,干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理)...

    原标题:干货 | App 自动化测试痛点(弹框及首页启动加载完成判断处理) 1. 常见痛点 App 自动化测试中有些常见痛点问题,如果框架不能很好的处理,就可能出现元素定位超时找不到的情况,自动化也就 ...

最新文章

  1. Where Should an Architect Begin?--reference
  2. JAVA方法调用中的解析与分派
  3. 游戏中的数学与物理学 第二版_在游戏中启蒙幼儿的数学能力和逻辑思维能力...
  4. PHP foreach遍历数组(多种方式)
  5. codeigniter:去掉 URL 中的 index.php
  6. neo4j merge
  7. linux 占用缓存前10_Ogre的不足与改进(Ogre2.0设计方案)-1.缓存优化
  8. 跨平台最好用笔记软件——Simplenote
  9. C#面向对象10 继承
  10. 基于adaboost算法的人脸检测_基于噪声检测的图像去噪算法
  11. HTML网页之日历代码
  12. nuc972 linux 升级,NUC972移植工作记录
  13. 矩阵的entries
  14. 淘宝链接转换成淘宝客链接--PHP
  15. 特斯拉进化论:舍命狂奔背后的生存哲学
  16. Chatbot(五)
  17. 群晖jellyfin外网访问
  18. 【多会议推荐】计算机主题,多高校单位主办,SCI会议征稿!
  19. 复合线转权属线lisp_请大神帮忙分析这一点处怎么可能是裂缝(检查多段线之间的缝隙)...
  20. 软件测试webtours飞机票bug档案,【松勤软件性能测试】Web Tours无法打开,怎么办?...

热门文章

  1. angularjs 实例_AngularJS服务示例教程
  2. HibernateEHCache –Hibernate二级缓存
  3. memcached 命令_Memcached Telnet命令示例
  4. 想学习C++,C++的未来怎么样?
  5. Java基础篇:循环语句之do-while循环
  6. Swagger 生成 PHP API 接口文档
  7. MVVM架构~Knockoutjs系列之text,value,attr,visible,with的数据绑定
  8. OpenStack Orchestration service (编排服务Heat)
  9. android gradle NDK简介
  10. java的JDK配置