文章目录
以material
主题为例,项目部分依赖如下:
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
查看java源码
从new AlertDialog.Builder(context)
切入。
package androidx.appcompat.app;
import androidx.appcompat.R;
public class AlertDialog extends AppCompatDialog implements DialogInterface {
protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
super(context, resolveDialogTheme(context, themeResId));
mAlert = new AlertController(getContext(), this, getWindow());
}
...
static int resolveDialogTheme(@NonNull Context context, @StyleRes int resid) {
// Check to see if this resourceId has a valid package ID.
if (((resid >>> 24) & 0x000000ff) >= 0x00000001) { // start of real resource IDs.
return resid;
} else {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
return outValue.resourceId;
}
}
public static class Builder {
private final AlertController.AlertParams P;
private final int mTheme;
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
...
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;
}
}
}
class AlertController {
public AlertController(Context context, AppCompatDialog di, Window window) {
...
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog,
R.attr.alertDialogStyle, 0);
mAlertDialogLayout = a.getResourceId(R.styleable.AlertDialog_android_layout, 0);
...
}
}
总结
通过AlertDialog.Builder
构造AlertDialog
,可传入themeResId
指定弹窗样式。
themeResId
默认值为应用主题中的alertDialogTheme
,同alertDialogStyle
一起决定弹窗外观。
查看样式
本例应用主题@style/Theme.MaterialComponents.DayNight.NoActionBar
alertDialogStyle
<!-- # alertDialogStyle 👇 -->
<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>
<style name="Base.AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat"/>
<style name="AlertDialog.AppCompat.Light" parent="Base.AlertDialog.AppCompat.Light"/>
<!-- # alertDialogStyle 👆 -->
<style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
...
<item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
<item name="buttonBarPositiveButtonStyle">?attr/buttonBarButtonStyle</item>
<item name="buttonBarNegativeButtonStyle">?attr/buttonBarButtonStyle</item>
<item name="buttonBarNeutralButtonStyle">?attr/buttonBarButtonStyle</item>
...
<item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog.Alert</item>
<item name="alertDialogStyle">@style/AlertDialog.AppCompat.Light</item>
<item name="alertDialogCenterButtons">false</item>
</style>
<style name="Base.Theme.AppCompat.Light" parent="Base.V7.Theme.AppCompat.Light">
</style>
<style name="Theme.AppCompat.Light" parent="Base.Theme.AppCompat.Light"/>
<style name="Platform.MaterialComponents.Light" parent="Theme.AppCompat.Light"/>
<style name="Base.V14.Theme.MaterialComponents.Light.Bridge" parent="Platform.MaterialComponents.Light">
</style>
<style name="Platform.MaterialComponents.Light" parent="Theme.AppCompat.Light"/>
<style name="Base.V14.Theme.MaterialComponents.Light.Bridge" parent="Platform.MaterialComponents.Light">
</style>
alertDialogTheme
<!-- # alertDialogTheme 👇 -->
<style name="Base.V7.ThemeOverlay.AppCompat.Dialog" parent="Base.ThemeOverlay.AppCompat">
<item name="android:windowTitleStyle">@style/RtlOverlay.DialogWindowTitle.AppCompat</item>
</style>
<style name="Base.ThemeOverlay.AppCompat.Dialog" parent="Base.V7.ThemeOverlay.AppCompat.Dialog"/>
<style name="Base.ThemeOverlay.AppCompat.Dialog.Alert">
</style>
<style name="ThemeOverlay.AppCompat.Dialog.Alert" parent="Base.ThemeOverlay.AppCompat.Dialog.Alert"/>
<style name="Base.V14.ThemeOverlay.MaterialComponents.Dialog.Alert" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<!-- Widget styles -->
<item name="buttonBarButtonStyle">@style/Widget.MaterialComponents.Button.TextButton.Dialog.Flush</item>
</style>
<style name="Base.ThemeOverlay.MaterialComponents.Dialog.Alert" parent="Base.V14.ThemeOverlay.MaterialComponents.Dialog.Alert"/>
<style name="ThemeOverlay.MaterialComponents.Dialog.Alert" parent="Base.ThemeOverlay.MaterialComponents.Dialog.Alert"/>
<!-- # alertDialogTheme 👆 -->
<style name="Base.V14.Theme.MaterialComponents.Light" parent="Base.V14.Theme.MaterialComponents.Light.Bridge">
<item name="alertDialogTheme">@style/ThemeOverlay.MaterialComponents.Dialog.Alert</item>
</style>
<style name="Base.V21.Theme.MaterialComponents.Light" parent="Base.V14.Theme.MaterialComponents.Light">
<item name="android:alertDialogTheme">@style/ThemeOverlay.MaterialComponents.Light.Dialog.Alert.Framework</item>
</style>
<style name="Base.Theme.MaterialComponents.Light" parent="Base.V21.Theme.MaterialComponents.Light"/>
<style name="Theme.MaterialComponents.Light" parent="Base.Theme.MaterialComponents.Light"/>
<style name="Theme.MaterialComponents.Light.NoActionBar">
</style>
<style name="Theme.MaterialComponents.DayNight.NoActionBar" parent="Theme.MaterialComponents.Light.NoActionBar"/>
查看布局
布局文件由alertDialogStyle
之layout
引入。
abc_alert_dialog_material.xml
<androidx.appcompat.widget.AlertDialogLayout>
<include layout="@layout/abc_alert_dialog_title_material"/>
<FrameLayout android:id="@+id/contentPanel">
...
<TextView
style="@style/TextAppearance.AppCompat.Subhead"
android:id="@android:id/message"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
/>
...
</FrameLayout>
...
<include layout="@layout/abc_alert_dialog_button_bar_material"/>
</androidx.appcompat.widget.AlertDialogLayout>
abc_alert_dialog_title_material.xml
...
<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"
/>
...
abc_alert_dialog_button_bar_material.xml
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:layoutDirection="locale"
android:orientation="horizontal"
android:paddingLeft="12dp"
android:paddingTop="4dp"
android:paddingRight="12dp"
android:paddingBottom="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"
/>
</LinearLayout>
...
总结
- 要改消息样式,直接改
TextAppearance.AppCompat.Subhead
- 要改标题样式,改
alertDialogTheme
里面相应windowTitleStyle
,如TextAppearance.AppCompat.Title
- 要改按钮样式,改
alertDialogTheme
里面相应buttonBarButtonStyle
,如Widget.MaterialComponents.Button.TextButton.Dialog
- 要改弹窗布局,改
alertDialogStyle
里面相应layout
,如abc_alert_dialog_button_bar_material.xml