Android中建造者模式自定义Dialog

一、简述

    由于Android系统的碎片化比较严重,加之Android采用开源方式,世界各大OEM厂商都对自家的Android系统进行了深度定制,那么这些原因会给我们开发者带来一些个麻烦,比如说,我们要开发一款App就要考虑到这款App尽量在不同系统和不同OEM深度定制的Android系统中弹出的对话框样式界面相同,那么这时候我们就不得不自定义自己的Dialog对话框。

二、实现的大体思路

    我在此会编写一个demo,demo中设计一个类CommonDialog(当然这个类也是这个自定义Dialog的核心),这个类完成之后能够像Android系统提供的AlertDialog一样好用,那么这个类的编写的大致思路和所需的准备材料如下:

1、设计模式:   

 我们在自定义Dialog的时候采用的是建造者模式,如果对建造者模式不太熟悉的可以参考下这篇文章《建造者模式》。我们在使用建造模式构建复杂对象时候通常会这样做:

      ①由于是用Builder模式来创建某个对象,因此就没有必要再定义一个Builder接口,直接提供一个具体的建造者类就可以了。

   对于创建一个复杂的对象,可能会有很多种不同的选择和步骤,干脆去掉“导演者”,把导演者的功能和Client的功能合并起来,也就是说,Client这个时候就相当于导演者,它来指导构建器类去构建需要的复杂对象。

2、样式的定义:

    关于样式的定义,一般情况下配置一些基本的属性标签,比如,背景颜色及透明程度、是否有标题  、是否浮现在activity之上等。

3、Dialog的布局设计:

     我参照之前项目中的升级对话框就写了一个类似的Dialog,如下图:

                               


三、具体的代码实现

    1、那么我们首先来自定义一个style样式,该样式继承自Theme.Dialog,具体的代码实现如下:

    

      <style name="Dialog" parent="android:style/Theme.Dialog">
          <item name="android:background">@null</item>
          <item name="android:windowBackground">@android:color/transparent</item>
          <item name="android:windowNoTitle">true</item>
          <item name="android:windowIsFloating">true</item>
          <item name="android:spacing">350dp</item>
       </style>
          上面的样式主要设置了一些对话框的基本信息,这里不再一一介绍。


2、按照上面给出的图片所示,书写的布局文件代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_dialog_title"
        style="@style/dilog_header"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#e6e6fa"
        android:gravity="center_vertical"
        android:paddingLeft="20.0dp" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:background="#63B8FF" />

    <LinearLayout
        android:id="@+id/dialog_llyout_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" >

        <TextView
            android:id="@+id/dialog_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/textview_border"
            android:lineSpacingMultiplier="1.5"
            android:minHeight="80.0dp"
            android:paddingBottom="15.0dp"
            android:paddingLeft="20.0dp"
            android:paddingRight="20.0dp"
            android:paddingTop="15.0dp"
            android:textSize="18sp" 
            android:textColor="#000000"
            />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#B4CDCD" />

    <LinearLayout
        android:id="@+id/dialog_btn"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tv_dialog_pos"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#e6e6fa"
            android:gravity="center"
            android:text="下次再说"
            android:textColor="#000000" />

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="#B4CDCD" />

        <TextView
            android:id="@+id/tv_dialog_neg"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#e6e6fa"
            android:gravity="center"
            android:text="立即升级"
            android:textColor="#000000" />
    </LinearLayout>

</LinearLayout>

3、利用建造者模式编写核心类:

   、CommonDialog类

        这个CommonDialog作为建造对象其实并没有什么具体的逻辑问题,代码如下:


   public class CommonDialog extends Dialog {
                 public CommonDialog(Context context) {
                         super(context);
                 }

                 public CommonDialog(Context context, int themeResId) {
                          super(context, themeResId);
                 }

                  protected CommonDialog(Context context, boolean cancelable,
                          OnCancelListener cancelListener) {
                          super(context, cancelable, cancelListener);
                   }
 
             }

  ②Builder类

      这个类作为建造CommonDialog的核心类,它所建造的对象和实现的逻辑不是那么简单,而且它与CommonDialog的关系相当的暧昧,所以我们就将Builder作为CommonDialog的内部类,具体的代码如下:

/**
 * 自定义Dialog类---CommonDialog
 * 
 * @Time 2016年3月10日
 * @author lizy18
 */
public class CommonDialog extends Dialog {
 public CommonDialog(Context context) {
  super(context);
 }

 public CommonDialog(Context context, int themeResId) {
  super(context, themeResId);
 }

 protected CommonDialog(Context context, boolean cancelable,
   OnCancelListener cancelListener) {
  super(context, cancelable, cancelListener);
 }

 public static class Builder {
  private Context context;
  private String title;
  private String message;
  private String positiveButtonContent;
  private String negativeButtonContent;
  private OnClickListener positiveButtonListener;
  private OnClickListener negativeButtonListener;
  private View contentView;

  /**
   * 建造器的构造方法:
   * 
   * @param context
   */
  public Builder(Context context) {
   this.context = context;
  }

  /**
   * 利用字符串设置title
   * 
   * @Time 2016年3月10日
   * @Author lizy18
   * @param title
   * @return Builder
   */
  public Builder setTitle(String title) {
   this.title = title;
   return this;
  }

  /**
   * 利用资源id设置title
   * 
   * @Time 2016年3月10日
   * @Author lizy18
   * @param title
   * @return Builder
   */
  public Builder setTitle(int title) {
   this.title = (String) context.getText(title);
   return this;
  }

  public Builder setMessage(String message) {
   this.message = message;
   return this;
  }

  public Builder setPositiveButton(String text, OnClickListener listener) {
   this.positiveButtonContent = text;
   this.positiveButtonListener = listener;
   return this;
  }

  public Builder setPositiveButton(int textId, OnClickListener listener) {
   this.positiveButtonContent = (String) context.getText(textId);
   this.positiveButtonListener = listener;
   return this;
  }

  public Builder setNegativeButton(String text, OnClickListener listener) {
   this.negativeButtonContent = text;
   this.negativeButtonListener = listener;
   return this;
  }

  public Builder setNegativeButton(int textId, OnClickListener listener) {
   this.negativeButtonContent = (String) context.getText(textId);
   this.negativeButtonListener = listener;
   return this;
  }

  public Builder setContentView(View v) {
   this.contentView = v;
   return this;
  }

  public CommonDialog create() {
   /**
    * 利用我们刚才自定义的样式初始化Dialog
    */
   final CommonDialog dialog = new CommonDialog(context,
     R.style.Dialog);
   /**
    * 下面就初始化Dialog的布局页面
    */
   LayoutInflater inflater = (LayoutInflater) context
     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   View dialogLayoutView = inflater.inflate(R.layout.dialog_layout,
     null);
   dialog.addContentView(dialogLayoutView, new LayoutParams(
     LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
   if (!TextUtils.isEmpty(title)) {
    ((TextView) dialogLayoutView.findViewById(R.id.tv_dialog_title))
      .setText(title);
   } else {
    Log.w(context.getClass().toString(), "未设置对话框标题!");
   }
   if (!TextUtils.isEmpty(message)) {
    ((TextView) dialogLayoutView.findViewById(R.id.dialog_content))
      .setText(message);
   } else if (contentView != null) {
    ((LinearLayout) dialogLayoutView
      .findViewById(R.id.dialog_llyout_content))
      .removeAllViews();
    ((LinearLayout) dialogLayoutView
      .findViewById(R.id.dialog_llyout_content)).addView(
      contentView, new LayoutParams(
        LayoutParams.MATCH_PARENT,
        LayoutParams.WRAP_CONTENT));
   } else {
    Log.w(context.getClass().toString(), "未设置对话框提示内容!");
   }

   if (!TextUtils.isEmpty(positiveButtonContent)) {
    ((TextView) dialogLayoutView.findViewById(R.id.tv_dialog_pos))
      .setText(positiveButtonContent);
    if (positiveButtonListener != null) {
     ((TextView) dialog.findViewById(R.id.tv_dialog_pos))
       .setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
         positiveButtonListener.onClick(dialog, -1);
        }
       });

    }
   } else {
    ((TextView) dialogLayoutView.findViewById(R.id.tv_dialog_pos))
      .setVisibility(View.GONE);
   }

   if (!TextUtils.isEmpty(negativeButtonContent)) {
    ((TextView) dialogLayoutView.findViewById(R.id.tv_dialog_neg))
      .setText(negativeButtonContent);
    if (negativeButtonListener != null) {
     ((TextView) dialogLayoutView
       .findViewById(R.id.tv_dialog_neg))
       .setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
         negativeButtonListener.onClick(dialog, -2);
        }
       });
    }
   } else {
    ((TextView) dialogLayoutView.findViewById(R.id.tv_dialog_neg))
      .setVisibility(View.GONE);
   }
   /**
    * 将初始化完整的布局添加到dialog中
    */
   dialog.setContentView(dialogLayoutView);
   /**
    * 禁止点击Dialog以外的区域时Dialog消失
    */
   dialog.setCanceledOnTouchOutside(false);
   return dialog;
  }
 }

}

4、测试
     我们的所有工作到此结束,现在我们要看一下如何调用并测试一下好不好用,核心代码如下:
private void showCommonDialog() {
  CommonDialog.Builder builder = new CommonDialog.Builder(this);
  builder.setTitle("升级提示");
  builder.setMessage("发现新版本,请及时更新");
  builder.setPositiveButton("立即升级", new OnClickListener() {

   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
    Toast.makeText(MainActivity.this, "开始下载吧", Toast.LENGTH_SHORT)
      .show();
   }
  });
  builder.setNegativeButton("下次再说", new OnClickListener() {

   @Override
   public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
    Toast.makeText(MainActivity.this, "过几日再下载也不迟呀",
      Toast.LENGTH_SHORT).show();
   }
  });

  builder.create().show();
 }

经过测试还不错!另外我附上这个demo的完整代码并希望大家能够一起交流共同进步!
 
Demo的下载路径:Android利用建造者模式自定义Dialog


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值