Android 提供了 AlertDialog 类可通过其内部类 Builder 轻松创建对话框窗口,但是没法对这个对话框窗口进行定制,为了修改 AlertDialog 窗口显示的外观,解决的办法就是创建一个指定的 AlertDialog 和 AlertDialog.Builder 类。
定义外观
我们希望将上面默认的对话框外观修改为如下图所示的新对话框风格:
该对话框将支持下面特性:
- 可从资源或者字符串直接指定对话框标题
- 可从资源、字符串和自定义布局来设置对话框内容
- 可设置按钮和相应的事件处理
编写布局、样式和主题
该对话框使用一个定制的布局来输出内容,布局定义的id将用于访问标题 TextView,下面是定义文件:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
03 | < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
04 | android:orientation = "vertical" |
05 | android:layout_width = "fill_parent" |
06 | android:minWidth = "280dip" |
07 | android:layout_height = "wrap_content" > |
11 | android:orientation = "vertical" |
12 | android:background = "@drawable/header" |
13 | android:layout_width = "fill_parent" |
14 | android:layout_height = "wrap_content" > |
17 | style = "@style/DialogText.Title" |
19 | android:id = "@+id/title" |
20 | android:paddingRight = "8dip" |
21 | android:paddingLeft = "8dip" |
22 | android:background = "@drawable/title" |
23 | android:layout_width = "wrap_content" |
25 | android:layout_height = "wrap_content" /> |
30 | android:id = "@+id/content" |
31 | android:orientation = "vertical" |
32 | android:background = "@drawable/center" |
34 | android:layout_width = "fill_parent" |
35 | android:layout_height = "wrap_content" > |
38 | style = "@style/DialogText" |
39 | android:id = "@+id/message" |
40 | android:padding = "5dip" |
42 | android:layout_width = "fill_parent" |
43 | android:layout_height = "wrap_content" /> |
48 | android:orientation = "horizontal" |
49 | android:background = "@drawable/footer" |
51 | android:layout_width = "fill_parent" |
52 | android:layout_height = "wrap_content" > |
55 | android:id = "@+id/positiveButton" |
56 | android:layout_marginTop = "3dip" |
57 | android:layout_width = "0dip" |
59 | android:layout_weight = "1" |
60 | android:layout_height = "wrap_content" |
61 | android:singleLine = "true" /> |
64 | android:id = "@+id/negativeButton" |
66 | android:layout_marginTop = "3dip" |
67 | android:layout_width = "0dip" |
68 | android:layout_weight = "1" |
69 | android:layout_height = "wrap_content" |
70 | android:singleLine = "true" /> |
根节点 LinearLayout 的宽度设置为 fill_parent 而最小的宽度是 280dip ,因此对话框的宽度将始终为屏幕宽度的 87.5%
自定义的主题用于声明对话框是浮动的,而且使用自定义的背景和标题视图:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
04 | < style name = "Dialog" parent = "android:style/Theme.Dialog" > |
05 | < item name = "android:windowBackground" >@null</ item > |
07 | < item name = "android:windowNoTitle" >true</ item > |
08 | < item name = "android:windowIsFloating" >true</ item > |
接下来我们需要定义对话框的标题和消息的显示:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
04 | < style name = "DialogText" > |
05 | < item name = "android:textColor" >#FF000000</ item > |
07 | < item name = "android:textSize" >12sp</ item > |
10 | < style name = "DialogText.Title" > |
11 | < item name = "android:textSize" >16sp</ item > |
13 | < item name = "android:textStyle" >bold</ item > |
编写对话框和 Builder 类
最好我们要提供跟 AletDialog.Builder 类一样的方法:
001 | package net.androgames.blog.sample.customdialog.dialog; |
003 | import net.androgames.blog.sample.customdialog.R; |
004 | import android.app.Dialog; |
005 | import android.content.Context; |
006 | import android.content.DialogInterface; |
007 | import android.view.LayoutInflater; |
008 | import android.view.View; |
009 | import android.view.ViewGroup.LayoutParams; |
010 | import android.widget.Button; |
011 | import android.widget.LinearLayout; |
012 | import android.widget.TextView; |
016 | * Create custom Dialog windows for your application |
017 | * Custom dialogs rely on custom layouts wich allow you to |
018 | * create and use your own look & feel. |
020 | * Under GPL v3 : http://www.gnu.org/licenses/gpl-3.0.html |
022 | * @author antoine vianey |
025 | public class CustomDialog extends Dialog { |
027 | public CustomDialog(Context context, int theme) { |
028 | super (context, theme); |
031 | public CustomDialog(Context context) { |
036 | * Helper class for creating a custom dialog |
038 | public static class Builder { |
040 | private Context context; |
041 | private String title; |
042 | private String message; |
043 | private String positiveButtonText; |
044 | private String negativeButtonText; |
045 | private View contentView; |
047 | private DialogInterface.OnClickListener |
048 | positiveButtonClickListener, |
049 | negativeButtonClickListener; |
051 | public Builder(Context context) { |
052 | this .context = context; |
056 | * Set the Dialog message from String |
060 | public Builder setMessage(String message) { |
061 | this .message = message; |
066 | * Set the Dialog message from resource |
070 | public Builder setMessage( int message) { |
071 | this .message = (String) context.getText(message); |
076 | * Set the Dialog title from resource |
080 | public Builder setTitle( int title) { |
081 | this .title = (String) context.getText(title); |
086 | * Set the Dialog title from String |
090 | public Builder setTitle(String title) { |
096 | * Set a custom content view for the Dialog. |
097 | * If a message is set, the contentView is not |
098 | * added to the Dialog... |
102 | public Builder setContentView(View v) { |
103 | this .contentView = v; |
108 | * Set the positive button resource and it's listener |
109 | * @param positiveButtonText |
113 | public Builder setPositiveButton( int positiveButtonText, |
114 | DialogInterface.OnClickListener listener) { |
115 | this .positiveButtonText = (String) context |
116 | .getText(positiveButtonText); |
117 | this .positiveButtonClickListener = listener; |
122 | * Set the positive button text and it's listener |
123 | * @param positiveButtonText |
127 | public Builder setPositiveButton(String positiveButtonText, |
128 | DialogInterface.OnClickListener listener) { |
129 | this .positiveButtonText = positiveButtonText; |
130 | this .positiveButtonClickListener = listener; |
135 | * Set the negative button resource and it's listener |
136 | * @param negativeButtonText |
140 | public Builder setNegativeButton( int negativeButtonText, |
141 | DialogInterface.OnClickListener listener) { |
142 | this .negativeButtonText = (String) context |
143 | .getText(negativeButtonText); |
144 | this .negativeButtonClickListener = listener; |
149 | * Set the negative button text and it's listener |
150 | * @param negativeButtonText |
154 | public Builder setNegativeButton(String negativeButtonText, |
155 | DialogInterface.OnClickListener listener) { |
156 | this .negativeButtonText = negativeButtonText; |
157 | this .negativeButtonClickListener = listener; |
162 | * Create the custom dialog |
164 | public CustomDialog create() { |
165 | LayoutInflater inflater = (LayoutInflater) context |
166 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
168 | final CustomDialog dialog = new CustomDialog(context, |
170 | View layout = inflater.inflate(R.layout.dialog, null ); |
171 | dialog.addContentView(layout, new LayoutParams( |
172 | LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); |
174 | ((TextView) layout.findViewById(R.id.title)).setText(title); |
176 | if (positiveButtonText != null ) { |
177 | ((Button) layout.findViewById(R.id.positiveButton)) |
178 | .setText(positiveButtonText); |
179 | if (positiveButtonClickListener != null ) { |
180 | ((Button) layout.findViewById(R.id.positiveButton)) |
181 | .setOnClickListener( new View.OnClickListener() { |
182 | public void onClick(View v) { |
183 | positiveButtonClickListener.onClick( |
185 | DialogInterface.BUTTON_POSITIVE); |
191 | layout.findViewById(R.id.positiveButton).setVisibility( |
195 | if (negativeButtonText != null ) { |
196 | ((Button) layout.findViewById(R.id.negativeButton)) |
197 | .setText(negativeButtonText); |
198 | if (negativeButtonClickListener != null ) { |
199 | ((Button) layout.findViewById(R.id.negativeButton)) |
200 | .setOnClickListener( new View.OnClickListener() { |
201 | public void onClick(View v) { |
202 | positiveButtonClickListener.onClick( |
204 | DialogInterface.BUTTON_NEGATIVE); |
210 | layout.findViewById(R.id.negativeButton).setVisibility( |
214 | if (message != null ) { |
215 | ((TextView) layout.findViewById( |
216 | R.id.message)).setText(message); |
217 | } else if (contentView != null ) { |
220 | ((LinearLayout) layout.findViewById(R.id.content)) |
222 | ((LinearLayout) layout.findViewById(R.id.content)) |
223 | .addView(contentView, |
225 | LayoutParams.WRAP_CONTENT, |
226 | LayoutParams.WRAP_CONTENT)); |
228 | dialog.setContentView(layout); |
使用自定义的 Builder
使用方法很简单:
02 | * Build the desired Dialog |
06 | public Dialog onCreateDialog( int dialogId) { |
10 | CustomDialog.Builder customBuilder = new |
11 | CustomDialog.Builder(CustomDialogActivity. this ); |
12 | customBuilder.setTitle( "Custom title" ) |
13 | .setMessage( "Custom body" ) |
14 | .setNegativeButton( "Cancel" , |
15 | new DialogInterface.OnClickListener() { |
16 | public void onClick(DialogInterface dialog, int which) { |
17 | CustomDialogActivity. this |
18 | .dismissDialog(CUSTOM_DIALOG); |
21 | .setPositiveButton( "Confirm" , |
22 | new DialogInterface.OnClickListener() { |
23 | public void onClick(DialogInterface dialog, int which) { |
27 | dialog = customBuilder.create(); |
30 | AlertDialog.Builder alertBuilder = new |
31 | AlertDialog.Builder(CustomDialogActivity. this ); |
32 | alertBuilder.setTitle( "Default title" ) |
33 | .setMessage( "Default body" ) |
34 | .setNegativeButton( "Cancel" , |
35 | new DialogInterface.OnClickListener() { |
36 | public void onClick(DialogInterface dialog, int which) { |
40 | .setPositiveButton( "Confirm" , |
41 | new DialogInterface.OnClickListener() { |
42 | public void onClick(DialogInterface dialog, int which) { |
43 | CustomDialogActivity. this |
44 | .dismissDialog(DEFAULT_DIALOG); |
47 | dialog = alertBuilder.create(); |
完整的代码下载: SampleCustomDialog
Enjoy !