LoginSignup
81
87

More than 1 year has passed since last update.

AlertDialogのスタイルをカスタマイズ

Last updated at Posted at 2016-12-11

この記事は、Android その3 Advent Calendar 2016 - Qiitaの12日目の記事です!


注意!!
この記事は、appcompat-v7のバージョン25.0.1で試した内容です。最新バージョン25.1.0では、android.support.v7.app.AlertControllerの実装が変更されており、使用できない箇所があります。


#AlertDialogのスタイルをカスタマイズ

Support Library v7 appcompat ライブラリを使用するると、Android 2.3(API レベル 9)以上のデバイスで、アプリでマテリアルデザインを使用することができ、ダイアログもマテリアルデザインになります。

import android.support.v7.app.AlertDialog;

// 省略

	AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
	builder.setTitle("確認");
	builder.setMessage("XXXしてもよろしいですか?");
	builder.setPositiveButton("はい", null);
	builder.setNegativeButton("いいえ", null);
	builder.setNeutralButton("キャンセル", null);
	builder.create().show();

device-2016-12-09-143313.png

NeutralButtonが左端にあり、PositiveButtonとNegativeButtonが右に寄ったデザインですね。

通常のユーザーが使用するアプリであればこのデザインでよいとは思いますが、幼児/高年齢向けアプリを考えたとき、もっと大きな文字で、押しやすいボタンのデザインにしたいと思ったので、ダイアログをカスタマイズしてみます。

styles.xml

まず、スタイルを定義します。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">

</style>

AlertDialog.Builderの、第二引数 int themeResIdにテーマを指定することでカスタムのスタイルの適用することができます。[AlertDialog.Builder | Android Developers](https://developer.android.com/reference/android/support/v7/app/AlertDialog.Builder.html#AlertDialog.Builder(android.content.Context, int))

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.MyAlertDialogStyle);

アプリすべてのダイアログにスタイルを適用する場合は、AppThemeのandroid:alertDialogThemeに指定します。

themes.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:alertDialogTheme">@style/MyAlertDialogStyle</item>
</style>

ボタンのテキストカラー

colorAccentを指定します。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
</style>

device-2016-12-11-220726.png

タイトルとボタンのテキストの大きさ

android:textSizeを指定します。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
    <item name="android:textSize">@dimen/dialog_text_size</item>
</style>

device-2016-12-11-221633.png

ボタンが縦に並んでしまいました...
メッセージのサイズは変更されませんね...

ダイアログの大きさを変更

android:windowMinWidthMajor, android:windowMinWidthMinorを指定します。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
    <item name="android:textSize">@dimen/dialog_text_size</item>
    <item name="android:windowMinWidthMajor">@dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
  • android:windowMinWidthMajor ... 端末が横向きの場合のダイアログの幅の最小サイズ
  • android:windowMinWidthMinor ... 端末が縦向きの場合のダイアログの幅の最小サイズ
dimenは画面全体の比率(%)で指定することができます。
dimens.xml
<resources>
    <item type="dimen" name="dialog_min_width_major">95%</item>
    <item type="dimen" name="dialog_min_width_minor">95%</item>
</resources>

device-2016-12-11-223226.png

テキストスタイル

android:textColorPrimaryを指定するとテキストカラーを変更できます。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
    <item name="android:textColorPrimary">@color/colorPrimary</item>
</style>

android:windowTitleStyleを定義するとタイトルのスタイルを変更できます。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
    <item name="android:windowTitleStyle">@style/windowTitleStyle</item>
</style>

<style name="windowTitleStyle" parent="TextAppearance.AppCompat.Large">
    <item name="android:textSize">@dimen/dialog_text_size</item>
</style>

メッセージのテキストサイズ

メッセージのテキストサイズを指定きる属性が見当たりませんでしたのでコードでハックします。

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.MyAlertDialogStyle);
builder.setTitle("確認");
builder.setMessage("XXXしてもよろしいですか?");
builder.setPositiveButton("はい", null);
builder.setNegativeButton("いいえ", null);
builder.setNeutralButton("キャンセル", null);

AlertDialog dialog = builder.show();

// メッセージテキストを変更する。
TextView textView = (TextView) dialog.findViewById(android.R.id.message);
textView.setTextSize(48.0f);

device-2016-12-11-224301.png

ボタンのスタイル

buttonBarNeutralButtonStyle, buttonBarNegativeButtonStyle, buttonBarPositiveButtonStyle で指定することが出来ます。

styles.xml
<style name="MyAlertDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">@color/primary</item>
    <item name="android:textSize">@dimen/dialog_text_size</item>
    <item name="android:windowMinWidthMajor">@dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@dimen/dialog_min_width_minor</item>

    <item name="buttonBarNeutralButtonStyle">@style/buttonBarButtonStyle.Neutral</item>
    <item name="buttonBarNegativeButtonStyle">@style/buttonBarButtonStyle.Negative</item>
    <item name="buttonBarPositiveButtonStyle">@style/buttonBarButtonStyle.Positive</item>

</style>
テキストカラー
styles.xml
<style name="buttonBarButtonStyle" parent="Widget.AppCompat.Button.Borderless.Colored">
</style>

<style name="buttonBarButtonStyle.Neutral">
</style>

<style name="buttonBarButtonStyle.Negative">
    <item name="android:textColor">@color/red</item>
</style>

<style name="buttonBarButtonStyle.Positive">
    <item name="android:textColor">@color/blue</item>
</style>

親(parent)に Widget.AppCompat.Button.Borderless.Colored を指定すると、テキストカラーのデフォルトがcolorAccentになります。

device-2016-12-11-230939.png

カラーボタン

親(parent)に Widget.AppCompat.Button.Coloredを指定すると、colorAccentを背景にしたボタンを配置されます。

styles.xml
<style name="buttonBarButtonStyle" parent="Widget.AppCompat.Button.Colored">
</style>

<style name="buttonBarButtonStyle.Neutral">
</style>

<style name="buttonBarButtonStyle.Negative">
    <item name="android:textColor">@color/red</item>
</style>

<style name="buttonBarButtonStyle.Positive">
    <item name="android:textColor">@color/blue</item>
</style>

device-2016-12-11-235950.png

背景

背景はのサイズを大きくしたり、カラーを変更したり場合には、android:backgroundを変更します。
リップル効果が着いた背景にしたい場合は、appcompatのソースを参考にするとよいでしょう。

背景カラーを変更したり場合には、app:backgroundTint を指定します。

<style name="buttonBarButtonStyle.Positive">
    <item name="backgroundTint">@color/colorAccent</item>
</style>

ボタンの配置

マテリアルデザイン以前のダイアログように、ボタンが中央に3つ並べたスタイルにしたい場合は、コードでハックします。

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.MyAlertDialogStyle);
builder.setTitle("確認");
builder.setMessage("XXXしてもよろしいですか?");
builder.setPositiveButton("はい", null);
// builder.setNegativeButton("いいえ", null);
builder.setNeutralButton("キャンセル", null);

AlertDialog dialog = builder.show();

// メッセージテキストを変更する。
TextView textView = (TextView) dialog.findViewById(android.R.id.message);
textView.setTextSize(48.0f);


// ボタンパネルのコンテナを取得する。
LinearLayout containerButtons = (LinearLayout) dialog.findViewById(R.id.buttonPanel);

// Space Viewを削除する。
containerButtons.removeView(containerButtons.getChildAt(1));

// ボタンパネルの子ViewのボタンのGravityをCENTERに設定する
containerButtons.setGravity(Gravity.CENTER);

// LinearLayoutの比率の合計を3に設定する。
containerButtons.setWeightSum(3.0f);

// 各ボタンを取得する。
Button button3 = (Button) containerButtons.findViewById(android.R.id.button3);
Button button2 = (Button) containerButtons.findViewById(android.R.id.button2);
Button button1 = (Button) containerButtons.findViewById(android.R.id.button1);

// 各ボタンの比率を指定する。
((LinearLayout.LayoutParams)button3.getLayoutParams()).weight = 1.0f;
((LinearLayout.LayoutParams)button2.getLayoutParams()).weight = 1.0f;
((LinearLayout.LayoutParams)button1.getLayoutParams()).weight = 1.0f;

// 各ボタンの幅を0にする。
((LinearLayout.LayoutParams)button3.getLayoutParams()).width = 0;
((LinearLayout.LayoutParams)button2.getLayoutParams()).width = 0;
((LinearLayout.LayoutParams)button1.getLayoutParams()).width = 0;

device-2016-12-12-104514.png

Layoutでハック

appcompat ライブラリで使用されているリソースを上書きすることで、ダイアログのデザインを変更することも可能です。

sdk/extras/android/support/v7/appcompat/res/layout/abc_alert_dialog_material.xml - android_tools - Git at Google

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/parentPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    <LinearLayout
            android:id="@+id/topPanel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        <LinearLayout
                android:id="@+id/title_template"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:gravity="center_vertical"
                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:scaleType="fitCenter"
                    android:src="@null"
                    style="@style/RtlOverlay.Widget.AppCompat.DialogTitle.Icon"/>
            <android.support.v7.widget.DialogTitle
                    android:id="@+id/alertTitle"
                    style="?attr/android:windowTitleStyle"
                    android:singleLine="true"
                    android:ellipsize="end"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textAlignment="viewStart" />
        </LinearLayout>
        <!-- If the client uses a customTitle, it will be added here. -->
    </LinearLayout>
    <FrameLayout
            android:id="@+id/contentPanel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:minHeight="48dp">
        <View android:id="@+id/scrollIndicatorUp"
              android:visibility="gone"
              android:layout_width="match_parent"
              android:layout_height="1dp"
              android:layout_gravity="top"
              android:background="?attr/colorControlHighlight"/>
        <android.support.v4.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">
                <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:paddingTop="@dimen/abc_dialog_padding_top_material"
                        android:paddingRight="?attr/dialogPreferredPadding"/>
                <View
                        android:id="@+id/textSpacerNoButtons"
                        android:visibility="gone"
                        android:layout_width="0dp"
                        android:layout_height="@dimen/abc_dialog_padding_top_material"/>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
        <View android:id="@+id/scrollIndicatorDown"
              android:visibility="gone"
              android:layout_width="match_parent"
              android:layout_height="1dp"
              android:layout_gravity="bottom"
              android:background="?attr/colorControlHighlight"/>
    </FrameLayout>
    <FrameLayout
            android:id="@+id/customPanel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            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" />
</LinearLayout>

sdk/extras/android/support/v7/appcompat/res/layout/abc_alert_dialog_button_bar_material.xml - android_tools - Git at Google

layout/abc_alert_dialog_button_bar_material.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.ButtonBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/buttonPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layoutDirection="locale"
    android:orientation="horizontal"
    android:paddingLeft="12dp"
    android:paddingRight="12dp"
    android:paddingTop="4dp"
    android:paddingBottom="4dp"
    android:gravity="bottom"
    app:allowStacking="@bool/abc_allow_stacked_button_bar"
    style="?attr/buttonBarStyle">
    <Button
        android:id="@android:id/button3"
        style="?attr/buttonBarNeutralButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <android.support.v4.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" />
</android.support.v7.widget.ButtonBarLayout>

<android.support.v4.widget.Space android:id="@+id/spacer"/> は必須です。削除するとエラーが発生します。

appcompat ライブラリで使用されているリソースを追うことで、何処でどのstyleや属性が使用しているか確認できますので、
ターゲットユーザーにとって使いやすいデザインにハックしてみたいと思います。

参考

81
87
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
81
87