Configuring the Layout of Android’s AlertDialog

Android’s AlertDialog.Builder is a handy little tool to create small dialogs for error messages, warnings, confirmation of delete actions, etc. But when it comes to adapting the layout to the general look and feel of your app there is unfortunately no good documentation available. This article summarizes my findings in this area.

 The structure of the AlertDialog layout

Objects of type AlertDialog are created by calling the create() or show() method of a properly configured AlertDialog.Builder object. There is a version of the constructor for AlertDialog.Builder which has the resource id of an XML style as parameter. Instead of using this parameter you can set the style with

<item name="android:alertDialogTheme">@style/... </item>

in the style file of your app. Some general style properties like windowBackground or dialog style properties like buttonBarStyle can be set this way but there are properties like the background of the message text that cannot be modified this way. To understand why, you have to look at the way an alert dialog constructs its layout:

AlertDialog delegates the job of creating the dialog’s layout to it’s superclass Dialog and to an Android internal class com.android.internal.app.AlertController. The AlertController class does this by using an XML layout file which is part of the Android SDK (for version 19 you find the different versions under …/platforms/android-19/data/res/values/alert_dialog…) and an XML style that you define in your app theme with

<item name="android:alertDialogStyle">@style/...</item>

Let’s have a look at the layout file first. As an example let’s take the standard holo design of Android SDK version 19 which I have abbreviated for this article:

...
<LinearLayout 
 ...
 android:orientation="vertical">
    <LinearLayout android:id="@+id/topPanel"
    ... 
        android:orientation="vertical">
        <View android:id="@+id/titleDividerTop"
            ...
            android:background="@android:color/holo_blue_light" />
        <LinearLayout android:id="@+id/title_template"
            ...
            android:orientation="horizontal"
            android:gravity="center_vertical|start"
            android:minHeight="@dimen/alert_dialog_title_height"
            ...>
            <ImageView android:id="@+id/icon"
                ... />
            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
                style="?android:attr/windowTitleStyle"
                ... />
        </LinearLayout>
        <View android:id="@+id/titleDivider"
            ...
            android:background="@android:color/holo_blue_light" />
    <!-- If the client uses a customTitle, it will be added here. -->
    </LinearLayout>
    <LinearLayout android:id="@+id/contentPanel"
        ...>
        <ScrollView android:id="@+id/scrollView"
        ...>
            <TextView android:id="@+id/message"
                style="?android:attr/textAppearanceMedium"
            .../>
        </ScrollView>
    </LinearLayout>
    ...
    <LinearLayout android:id="@+id/buttonPanel"
        ...
        android:minHeight="@dimen/alert_dialog_button_bar_height"
        android:orientation="vertical"
        android:divider="?android:attr/dividerHorizontal"
        android:showDividers="beginning"
        android:dividerPadding="0dip">
        <LinearLayout
            style="?android:attr/buttonBarStyle"
            ...
            android:orientation="horizontal">
            <Button android:id="@+id/button2"
                ...
                style="?android:attr/buttonBarButtonStyle"
                android:minHeight="@dimen/alert_dialog_button_bar_height"
            />
            <Button android:id="@+id/button3"
                ...
                style="?android:attr/buttonBarButtonStyle"
                android:minHeight="@dimen/alert_dialog_button_bar_height"
            />
            <Button android:id="@+id/button1"
                ...
                android:minHeight="@dimen/alert_dialog_button_bar_height"
                style="?android:attr/buttonBarButtonStyle"
             ... />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

As this is a complex structure let’s walk through this top down:

The top structure is a linear, vertically oriented layout that contains three vertically oriented layouts for the title, the message and the button bar.

Title

The linear layout for the title (topPanel) consists of views for the divider lines above (titleDividerTop) and below (titleDivider) the title and a horizontal linear layout (title_template) that contains the icon (icon) and the title text  itself (alertTitle). This is the part of the alert dialog that has the most restrictions:

The design of the divider lines is hard coded in the layout file and can therefore not be changed by a style parameter. Especially the color of the lines (Android’s holo_blue_light) will hurt the overall design of many apps. The only solution here is to adjust the view layout parameter after the AlertDialog has been shown:

// Set title divider color
AlertDialog alert = ... .show();
int titleDividerId = getResources().getIdentifier("titleDivider", "id", "android");
View titleDivider = alert.findViewById(titleDividerId);
if (titleDivider != null)
 titleDivider.setBackgroundColor(...));

The test of titleDivider against null is your life insurance against null pointer exceptions in case a new Android version decides to rename or remove the identifier of the title divider view.

The text view for the title itself is a special subclass of TextView called com.android.internal.widget.DialogTitle whose only difference to Android’s standard TextView is that it has a special onMeasure() method. Apart from the source code there is no documentation available for this class. As you can see in the layout file you can set a style for this view with a windowTitleStyle item. The text size of the title cannot (!) be set this way as in onMeasure() it is either read from a style file set with the textAppearanceMedium style item or (if this item is not available) from Androids predefined TextAppearance_Medium style.

Message

A standard text message is displayed in a TextView with the id message wrapped within a ScrollView. The TextView reads its style from the textAppearanceMedium style item as well. Therefore you can only set one text size for the title and the text message in your style file for the AlertDialog. If you want different sizes you can do it only programmatically after the AlertDialog has been shown.

Button Bar

The button bar consists of a linear layout with horizontal orientation (id buttonPanel) whose style can be set with a buttonBarStyle style item. It contains three buttons with the ids button2, button3 and button1 (yes, in this order) whose style can be set with buttonBarButtonStyle. In addition to that you can set a divider line on top of the button bar with a dividerHorizontal style item.

Setting the background of the AlertDialog items

AlertDialog leaves as already mentioned most of the layout work to an internal class called com.android.internal.app.AlertController. Among other things AlertController sets the backgrounds of the different areas of the dialog (title, message, buttons). It does so by reading a bunch of style parameters from a style file that is set with

<item name="android:alertDialogStyle">@style/MepAlertDialogStyle</item>

in the base theme of your app which means in parallel to setting alertDialogTheme (!). The style items look like this:

<style name="MyAlertDialogStyle">
    <item name="android:fullDark">@color/...</item>
    <item name="android:topDark">@color/...</item>
    <item name="android:centerDark">@color/...</item>
    <item name="android:bottomDark">@color/...</item>
    <item name="android:fullBright">@color/...</item>
    <item name="android:topBright">@color/...</item>
    <item name="android:centerBright">@color/...</item>
    <item name="android:bottomBright">@color/...</item>
    <item name="android:bottomMedium">@color/...</item>
    <item name="android:centerMedium">@color/...</item>
</style>

The way how AlertController does the background layout of the different views is  a bit complex. The details are only available in the sources of it’s setBackground() method. The general idea is to start with a light or dark background and then iterate between dark and bright when going from top through center to the bottom.

What top, center and bottom (plus “full” under certain circumstances) actually means depends on which views are actually available. For example top will be the title view if it exists. If not it will be the message view. A medium background is (if at all) only used for the button bar. The easiest way to get the style you want is to play a little with the style parameters until you have the backgrounds that you want. The centerMedium parameter that still exists is actually not used anymore by AlertController.

 A boilerplate for an AlertDialog style

The safest way to get a working style is to copy the style elements from one of Android’s standard styles and modify the items to your need. The following boilerplate is based upon the holo light theme of Android platform version 19.

<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
...
    <item name="android:alertDialogTheme">@style/MyAlertDialogTheme</item>
    <item name="android:alertDialogStyle">@style/MyAlertDialogStyle</item>
...
</style>

<style name="MyBorderlessButton">
    <!-- Set background drawable and text size of the buttons here -->
    <item name="android:background">...</item>
    <item name="android:textSize">...</item>
</style>

<style name="MyButtonBar">
    <!-- Define a background for the button bar and a divider between the buttons here -->
    <item name="android:divider">....</item>
    <item name="android:dividerPadding">...</item>
    <item name="android:showDividers">...</item>
    <item name="android:background">...</item>
</style>

<style name="MyAlertDialogTitle">
    <item name="android:maxLines">1</item>
    <item name="android:scrollHorizontally">true</item>
</style>

<style name="MyAlertTextAppearance">
    <!-- Set text size and color of title and message here -->
    <item name="android:textSize"> ... </item>
    <item name="android:textColor">...</item>
</style>

<style name="MepAlertDialogTheme">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowTitleStyle">@style/MyAlertDialogTitle</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:textAppearanceMedium">@style/MyAlertTextAppearance</item>
    <!-- If you don't want your own button bar style use
            @android:style/Holo.Light.ButtonBar.AlertDialog
            and
            ?android:attr/borderlessButtonStyle
    instead of @style/MyButtonBar and @style/MyBorderlessButton
-->
    <item name="android:buttonBarStyle">@style/MyButtonBar</item>
    <item name="android:buttonBarButtonStyle">@style/MyBorderlessButton</item>
</style>

<style name="MepAlertDialogStyle">
    <!-- Define background colors of title, message, buttons, etc. here -->
    <item name="android:fullDark">...</item>
    <item name="android:topDark">...</item>
    <item name="android:centerDark">...</item>
    <item name="android:bottomDark">...</item>
    <item name="android:fullBright">...</item>
    <item name="android:topBright">...</item>
    <item name="android:centerBright">...</item>
    <item name="android:bottomBright">...</item>
    <item name="android:bottomMedium">...</item>
    <item name="android:centerMedium">...</item>
</style>

6 thoughts on “Configuring the Layout of Android’s AlertDialog

Leave a Reply

Your email address will not be published. Required fields are marked *