Android 对话框支持自定义标题,内容,按钮和点击事件,基本上可以满足我们日常的使用。 但有时候我们想要修改对话框的文字,按钮颜色等,系统并没有提供对应的方法,正常情况下只能自定义布局。 接下来通过源码解析介绍几种修改 Dialog样式的方法。, B* o, `& S+ G7 K. k+ x5 r
一、Dialog源码解析8 r7 @' N+ C! s6 I$ m4 h
1.1 new AlertDialog.Builder(this).create()' E+ ]: c5 j9 h+ q4 j; @0 A
- protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
- super(context, resolveDialogTheme(context, themeResId));
- //创建AlertController,是Dialog布局相关代码
- mAlert = new AlertController(getContext(), this, getWindow());
- }
-
- @NonNull
- public AlertDialog create() {
- // We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
- // so we always have to re-set the theme
- final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
- P.apply(dialog.mAlert);
- dialog.setCancelable(P.mCancelable);
- if (P.mCancelable) {
- dialog.setCanceledOnTouchOutside(true);
- }
- dialog.setOnCancelListener(P.mOnCancelListener);
- dialog.setOnDismissListener(P.mOnDismissListener);
- if (P.mOnKeyListener != null) {
- dialog.setOnKeyListener(P.mOnKeyListener);
- }
- return dialog;
- }
-
- public void apply(AlertController dialog) {
- if (mCustomTitleView != null) {
- dialog.setCustomTitle(mCustomTitleView);
- } else {
- if (mTitle != null) {
- dialog.setTitle(mTitle);
- }
- if (mIcon != null) {
- dialog.setIcon(mIcon);
- }
- if (mIconId != 0) {
- dialog.setIcon(mIconId);
- }
- ..........
- AlertDialog 构造函数中会创建 AlertController,用来控制对话框的布局
- P.apply(dialog.mAlert); 将用户自定义的配置赋值给 AlertController
% w& s$ b$ \; y 1.2 AlertController1 _6 _# i% ^% U. h: G+ b+ e2 x& q
- public AlertController(Context context, AppCompatDialog di, Window window) {
- mContext = context;
- mDialog = di;
- mWindow = window;
- mHandler = new ButtonHandler(di);
-
- final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
- R.attr.alertDialogStyle, 0);
-
- mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
- mButtonPanelSideLayout = a.getResourceId(R.styleable.AlertDialog_buttonPanelSideLayout, 0);
-
- mListLayout = a.getResourceId(R.styleable.AlertDialog_listLayout, 0);
- mMultiChoiceItemLayout = a.getResourceId(R.styleable.AlertDialog_multiChoiceItemLayout, 0);
- mSingleChoiceItemLayout = a
- .getResourceId(R.styleable.AlertDialog_singleChoiceItemLayout, 0);
- mListItemLayout = a.getResourceId(R.styleable.AlertDialog_listItemLayout, 0);
- mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);
- mButtonIconDimen = a.getDimensionPixelSize(R.styleable.AlertDialog_buttonIconDimen, 0);
-
- a.recycle();
-
- /* We use a custom title so never request a window title */
- di.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
- }
R.attr.alertDialogStyle 是对话框的默认样式8 U' l, ]* B- W! h; O! h0 R- |
- <item name="alertDialogStyle">@style/AlertDialog.AppCompat</item>
- <style name="AlertDialog.AppCompat" parent="Base.AlertDialog.AppCompat"/>
- <style name="Base.AlertDialog.AppCompat" parent="android:Widget">
- <item name="android:layout">@layout/abc_alert_dialog_material</item>
- <item name="listLayout">@layout/abc_select_dialog_material</item>
- <item name="listItemLayout">@layout/select_dialog_item_material</item>
- <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
- <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
- <item name="buttonIconDimen">@dimen/abc_alert_dialog_button_dimen</item>
- </style>
上述代码可以看出,abc_alert_dialog_material 就是dialog的默认布局。
* k6 D1 h- V4 E7 Q) c- <androidx.appcompat.widget.AlertDialogLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/parentPanel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start|left|top"
- android:orientation="vertical">
-
- <include layout="@layout/abc_alert_dialog_title_material"/>
-
- <FrameLayout
- android:id="@+id/contentPanel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp">
-
- <View android:id="@+id/scrollIndicatorUp"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_gravity="top"
- android:background="?attr/colorControlHighlight"
- android:visibility="gone"/>
-
- <androidx.core.widget.NestedScrollView
- android:id="@+id/scrollView"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipToPadding="false">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <android.widget.Space
- android:id="@+id/textSpacerNoTitle"
- android:layout_width="match_parent"
- android:layout_height="@dimen/abc_dialog_padding_top_material"
- android:visibility="gone"/>
-
- <TextView
- android:id="@android:id/message"
- style="@style/TextAppearance.AppCompat.Subhead"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="?attr/dialogPreferredPadding"
- android:paddingRight="?attr/dialogPreferredPadding"/>
-
- <android.widget.Space
- android:id="@+id/textSpacerNoButtons"
- android:layout_width="match_parent"
- android:layout_height="@dimen/abc_dialog_padding_top_material"
- android:visibility="gone"/>
- </LinearLayout>
- </androidx.core.widget.NestedScrollView>
-
- <View android:id="@+id/scrollIndicatorDown"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_gravity="bottom"
- android:background="?attr/colorControlHighlight"
- android:visibility="gone"/>
-
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/customPanel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp">
-
- <FrameLayout
- android:id="@+id/custom"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </FrameLayout>
-
- <include layout="@layout/abc_alert_dialog_button_bar_material"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- </androidx.appcompat.widget.AlertDialogLayout>
标题布局:7 B, x6 F6 A- ~8 a5 u) n
- <!-- abc_alert_dialog_title_material: -->
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/topPanel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- If the client uses a customTitle, it will be added here. -->
-
- <LinearLayout
- android:id="@+id/title_template"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical|start|left"
- android:orientation="horizontal"
- android:paddingLeft="?attr/dialogPreferredPadding"
- android:paddingRight="?attr/dialogPreferredPadding"
- android:paddingTop="@dimen/abc_dialog_padding_top_material">
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginEnd="8dip"
- android:layout_marginRight="8dip"
- android:scaleType="fitCenter"
- android:src="@null"/>
-
- <androidx.appcompat.widget.DialogTitle
- android:id="@+id/alertTitle"
- style="?android:attr/windowTitleStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:ellipsize="end"
- android:singleLine="true"
- android:textAlignment="viewStart"/>
-
- </LinearLayout>
-
- <android.widget.Space
- android:id="@+id/titleDividerNoCustom"
- android:layout_width="match_parent"
- android:layout_height="@dimen/abc_dialog_title_divider_material"
- android:visibility="gone"/>
- </LinearLayout>
按钮布局:
1 d/ y, V; A& |4 P1 x; p& t- <!-- abc_alert_dialog_button_bar_material: -->
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/buttonPanel"
- style="?attr/buttonBarStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:fillViewport="true"
- android:scrollIndicators="top|bottom">
-
- <androidx.appcompat.widget.ButtonBarLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="bottom"
- android:layoutDirection="locale"
- android:orientation="horizontal"
- android:paddingBottom="4dp"
- android:paddingLeft="12dp"
- android:paddingRight="12dp"
- android:paddingTop="4dp">
-
- <Button
- android:id="@android:id/button3"
- style="?attr/buttonBarNeutralButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <android.widget.Space
- android:id="@+id/spacer"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:visibility="invisible"/>
-
- <Button
- android:id="@android:id/button2"
- style="?attr/buttonBarNegativeButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Button
- android:id="@android:id/button1"
- style="?attr/buttonBarPositiveButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- </androidx.appcompat.widget.ButtonBarLayout>
-
- </ScrollView>
二、修改Dialog样式
0 x# g8 i- g* S s$ E6 b. ^3 @) C0 L2.1 通过findViewById
$ U9 c) I2 r/ d* C+ F- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(msg);
- builder.setPositiveButton(getString(R.string.yes), null);
- AlertDialog dialog = builder.create();
- dialog.show();
- //直接通过id找到对应的控件
- Button button = dialog.findViewById(android.R.id.button1);
- //或者通过getButton方法也可以获取到
- Button button2 = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
这种修改方式必须在 show() 之后调用,否则会出现空指针异常。这个是因为,执行 show() 方法的时候,dialog才会初始化布局,具体源码可以查看 Dialog 的 onCreate 方法。& _3 [! L. b r3 b6 g) `, z2 {8 d
2.2 自定义style
' h$ e7 O0 R# Z# C, A 通过上面源码可以发现,Dialog三个按钮的样式如下:
- ]( \4 k7 }- M; A8 d$ T- buttonBarNeutralButtonStyle
- buttonBarNegativeButtonStyle
- buttonBarPositiveButtonStyle: N2 U1 |6 M& N6 W; D4 Y- l
- <Button
- android:id="@android:id/button3"
- style="?attr/buttonBarNeutralButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <android.widget.Space
- android:id="@+id/spacer"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:visibility="invisible"/>
-
- <Button
- android:id="@android:id/button2"
- style="?attr/buttonBarNegativeButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Button
- android:id="@android:id/button1"
- style="?attr/buttonBarPositiveButtonStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
自定义样式替换上述 style即可达到修改效果。
# H$ i8 Y2 ^5 G G 在style.xml添加如下代码:' {* D+ X3 y" }( E* |9 J% V* i
- <style name="accessPositiveBtnStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
- <item name="android:textColor">@color/test1</item>
- </style>
-
- <style name="accessNegativeBtnStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
- <item name="android:textColor">@color/test2</item>
- </style>
-
- <!-- 弹出框样式 -->
- <style name="testDialogTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
- <item name="buttonBarPositiveButtonStyle">@style/accessPositiveBtnStyle</item>
- <item name="buttonBarNegativeButtonStyle">@style/accessNegativeBtnStyle</item>
- </style>
具体使用:
) D7 S2 [3 Q I/ s0 X- AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.testDialogTheme);
- builder.setMessage("Test");
- builder.setCancelable(false);
- builder.setPositiveButton("确认", null);
- builder.setNegativeButton("取消", null);
- Dialog dialog = builder.create();
- dialog.show();
|