一、简述
由于Android系统的碎片化比较严重,加之Android采用开源方式,世界各大OEM厂商都对自家的Android系统进行了深度定制,那么这些原因会给我们开发者带来一些个麻烦,比如说,我们要开发一款App就要考虑到这款App尽量在不同系统和不同OEM深度定制的Android系统中弹出的对话框样式界面相同,那么这时候我们就不得不自定义自己的Dialog对话框。
二、实现的大体思路
1、设计模式:
①由于是用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;
}
}
}
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