Android 对话框支持自定义标题,内容,按钮和点击事件,基本上可以满足我们日常的使用。 但有时候我们想要修改对话框的文字,按钮颜色等,系统并没有提供对应的方法,正常情况下只能自定义布局。 接下来通过源码解析介绍几种修改 Dialog样式的方法。
# R/ o3 E) X5 D9 s8 s一、Dialog源码解析
2 f+ b1 X. n4 X1.1 new AlertDialog.Builder(this).create()! V6 f q% {$ J# T* N# Z' k* u
- 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); 将用户自定义的配置赋值给 AlertController6 l6 ?: Y* b$ c- I% k9 s/ u/ Q3 H- i
1.2 AlertController$ z9 }2 s* `" {
- 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 是对话框的默认样式+ w' R$ i+ D4 t' O
- <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的默认布局。
/ m/ X( D* K0 v3 X- <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>
标题布局:
s* i7 \# d- @2 T! j( E- <!-- 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>
按钮布局:
( f1 u" O/ Y* b( `' ~- <!-- 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样式 u5 V' X$ J _! a5 }
2.1 通过findViewById2 w2 p, A5 G% e' H/ @ \, p" T+ _- Y
- 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 方法。
9 x$ K: U! |" e" z2.2 自定义style
3 v; p% ~: X, e: d1 x# w 通过上面源码可以发现,Dialog三个按钮的样式如下:
" J1 q- C8 y4 t- buttonBarNeutralButtonStyle
- buttonBarNegativeButtonStyle
- buttonBarPositiveButtonStyle' a" e7 h3 ] S4 I% L7 ^
- <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即可达到修改效果。: o, Q3 Y* y! r
在style.xml添加如下代码:
7 G0 G* H) U# S0 e- <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>
具体使用:
0 Q9 P8 S% R% P5 a- 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();
|