考拉Android统一弹框

满堂花醉三千客,一剑霜寒十四洲。这篇文章主要讲述考拉Android统一弹框相关的知识,希望能为你提供帮助。
作者:钱成杰


背景

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

目标

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

怎么做?

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

考拉Android统一弹框

文章图片


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

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

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

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

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

样式

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

考拉Android统一弹框

文章图片


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是通用样式类:

考拉Android统一弹框

文章图片


KaolaBottomDialog是底部弹出浮层:

考拉Android统一弹框

文章图片


KaolaBottomConfirmDialog是底部确认浮层:

考拉Android统一弹框

文章图片


KaolaBottomCloseDialog是底部带关闭弹框:

考拉Android统一弹框

文章图片


【考拉Android统一弹框】ExpectPickUpTimeDialog是时间选择器浮层:

考拉Android统一弹框

文章图片


通用弹框的文案也支持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()  {                @Override                 public  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中去构建,再使用等等。




网易云产品免费体验馆,无套路试用,零成本体验云计算价值。  


本文来自网易实践者社区,经作者钱成杰授权发布
更多网易研发、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】  SpringBoot入门(四)——自动配置
【推荐】  SpringFox 初体验
【推荐】  Lily-一个埋点管理工具


    推荐阅读