在Android的应用中,很多时候,都会利用到 AlertDialog 来弹出信息,或者让用户进行选择,或者告知用户某些信息,而系统自带的背景效果,一般不能够满足需求,所以很多时候,就会存在自定义 AlertDialog 的需求。其实不仅是AlertDialog,为了完善一款应用,很多控件都需要自定义,比如前面文章中提到过的EditText 等。
今天就讲一下如何在Android中自定义 AlertDialog,请先看下面的效果图:
当点击“取消”或者“保存”按钮的时候,都会弹出对话框来通知用户,而这个对话框就是自定义的AlertDialog。
1)第一步:自定义布局,如下:
<?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:background="@drawable/shape_alert_dialog"
android:minWidth="280dp"
android:orientation="vertical" >
<TextView
android:id="@+id/tvAlertDialogTitle"
android:textSize="20sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:textColor="#FFFFFF"
android:layout_height="50dp"
android:layout_gravity="center"
android:gravity="center" />
<View
android:id="@+id/vTitleLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/line_divider" >
</View>
<TextView
android:id="@+id/tvAlertDialogMessage"
android:layout_width="match_parent"
android:textSize="16sp"
android:layout_height="50dp"
android:visibility="gone" />
<View
android:id="@+id/vMessageLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/line_divider"
android:visibility="gone" >
</View>
<RelativeLayout
android:id="@+id/rlAlertDialogButtons"
android:layout_width="270dp"
android:layout_marginBottom="10dp"
android:layout_height="50dp"
android:layout_gravity="center" >
<Button
android:id="@+id/btnAlertDialogNegative"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_margin="5dp"
android:textColor="#FFFFFF"
android:background="@drawable/shape_alert_button"
android:gravity="center" />
<Button
android:id="@+id/btnAlertDialogPositive"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_margin="5dp"
android:textColor="#FFFFFF"
android:background="@drawable/shape_alert_button"
android:gravity="center" />
</RelativeLayout>
</LinearLayout>
在上面的布局,定义了两个TextView,分别用来展示标题(Title)和信息(Message),还包括两条分隔线,最下面是两个按钮,至于具体的风格是怎么样的,就由各位发挥了。
2)第二步,我们要创建一个CustomAlertDialog类,继承Dialog类,为了延续Android原先的代码风格,我们可以模仿原来的AlertDialog类,创建builder类,具体代码如下:
2.1)首先是构造函数:
public class CustomAlertDialog extends Dialog {
public CustomAlertDialog(Context context) {
super(context);
}
public CustomAlertDialog(Context context, int themeId) {
super(context, themeId);
}
在这里,定义了其中一个构造函数,它的第二个参数是一个themeID,这是因为要利用系统原先的Dialog的属性,所以会继承系统的Dialog主题,进行修改,在styles.xml中定义如下:
<!-- Custom Alert Dialog -->
<style name="CustomAlertDialog" parent="android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
</style>
在这个style中,
a)会将Dialog的windowBackground属性设置为透明,从而去掉系统原先默认对话框的背景,
b)将系统对话框的标题给去掉,
c)对话框的飘浮属性要设置为true,使得这个对话框可以浮在View上面。
2.2)创建Builder类,里面会依照AlertDialog类的方法,设置我们需要的方法,比如在上面的demo中,只需要”确定“跟”取消“按钮,"标题”跟“信息”这几项,所以我们就不需要去实现其他的方法了,具体代码如下:
public static class Builder {
private Context mContext;
private String mTitle, mMessage;
private String mPositiveButtonText, mNegativeButtonText;
private OnClickListener mPositiveButtonClickListener,
mNegativeButtonClickListener;
public Builder(Context context) {
mContext = context;
}
public Builder setTitle(int resId) {
mTitle = (String) mContext.getText(resId);
return this;
}
public Builder setTitle(String title) {
mTitle = title;
return this;
}
public Builder setMessage(int resId) {
mMessage = (String) mContext.getText(resId);
return this;
}
public Builder setMessage(String message) {
mMessage = message;
return this;
}
public Builder setPositiveButton(int positiveButtonTextId,
OnClickListener listener) {
mPositiveButtonText = (String) mContext
.getText(positiveButtonTextId);
mPositiveButtonClickListener = listener;
return this;
}
public Builder setPositiveButton(String positiveButtonText,
OnClickListener listener) {
mPositiveButtonText = positiveButtonText;
mPositiveButtonClickListener = listener;
return this;
}
public Builder setNegativeButton(int negativeButtonTextId,
OnClickListener listener) {
mNegativeButtonText = (String) mContext
.getText(negativeButtonTextId);
mNegativeButtonClickListener = listener;
return this;
}
public Builder setNegativeButton(String negativeButtonText,
OnClickListener listener) {
mNegativeButtonText = negativeButtonText;
mNegativeButtonClickListener = listener;
return this;
}
public CustomAlertDialog create() {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.custom_alert_dialog, null);
final CustomAlertDialog customAlertDialog = new CustomAlertDialog(
mContext, R.style.CustomAlertDialog);
customAlertDialog.addContentView(view, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
TextView tvAlertTitle = (TextView) view
.findViewById(R.id.tvAlertDialogTitle);
tvAlertTitle.setText(mTitle);
if (!TextUtils.isEmpty(mMessage)) {
TextView tvAlertDialogMessage = (TextView) view
.findViewById(R.id.tvAlertDialogMessage);
tvAlertDialogMessage.setText(mMessage);
View vMessageLine = (View)view.findViewById(R.id.vMessageLine);
vMessageLine.setVisibility(View.VISIBLE);
}
Button btnPositive = (Button) view
.findViewById(R.id.btnAlertDialogPositive);
if (!TextUtils.isEmpty(mPositiveButtonText)) {
btnPositive.setText(mPositiveButtonText);
if (mPositiveButtonClickListener != null) {
btnPositive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPositiveButtonClickListener.onClick(
customAlertDialog, BUTTON_POSITIVE);
}
});
}
} else {
btnPositive.setVisibility(View.GONE);
}
Button btnNegative = (Button) view
.findViewById(R.id.btnAlertDialogNegative);
if (!TextUtils.isEmpty(mNegativeButtonText)) {
btnNegative.setText(mNegativeButtonText);
if (mNegativeButtonClickListener != null) {
btnNegative.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNegativeButtonClickListener.onClick(
customAlertDialog, BUTTON_NEGATIVE);
}
});
}else{
btnNegative.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
customAlertDialog.dismiss();
}
});
}
} else {
btnNegative.setVisibility(View.GONE);
}
if (View.VISIBLE == btnPositive.getVisibility()
&& View.GONE == btnNegative.getVisibility()) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) btnPositive
.getLayoutParams();
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
btnPositive.setLayoutParams(layoutParams);
}
return customAlertDialog;
}
public CustomAlertDialog show() {
CustomAlertDialog dialog = create();
dialog.show();
return dialog;
}
在上面,可以看到 setTitle,setMessage,setPositiveButton和setNegativeButton等都会有两个实现,其中一个是接收资源id,一个是直接接收字符串。
后面的就是 create 方法,在这里,
a)会利用LayoutInflater将我们最前面定义的布局文件给解析出来,设置给View变量,
b)同时,我们会利用前面定义的带themeId的构造函数,创建一个CustomAlertDialog对象,并将布局给加载到对话框上面。
c)将 Title,Message和 PositiveButton,NegativeButton等对应控件的内容给初始化,当然,需要根据参数值的判断,当我们在创建这个对话框的时候,有赋值的话,对需要去初始化,比如,Title 是必须的,而Message就不是必须的,同样,NegativeButton也不是必须的,所以需要根据其实际逻辑去判断要不要展现。
d)因为在定义布局的时候,是定义了两个按钮的,它们是一样大的,左右并排,那么如果只有一个按钮的话,就需要将其居中放置(其实在这里,我没有实现不改变大小,居中放置,所以只是将显示的按钮整个变大,居中放置,还没想明白为什么不行)。
e)最后定义一个show方法,将对话框给显示出来。
f)在Builder定义了两个 DialogInterface.OnClickListener,当点击我们布局的按钮的时候,会在按钮的View.OnClickListener方法中去调用DialogInterface.OnClickListener的onClick方法,而我们在Activity中创建AlertDialog的时候会去实现这个接口的方法。
2.3)在Activity中创建CustomAlertDialog,其实跟创建普通的AlertDialog方法一样,因为我们都是照着它的方法来实现的,只是去掉了一些我们不需要的方法,代码如下:
new CustomAlertDialog.Builder(context)
.setTitle(title)
.setNegativeButton(context.getString(R.string.dialog_no), null)
.setPositiveButton(context.getString(R.string.dialog_yes), listener)
.show();
嗯,到这里,我们的自定义AlertDialog就实现了。