探究AlertDialog布局及样式

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"/>

查看布局

布局文件由alertDialogStylelayout引入。

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
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值