在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就实现了。