ちょっと話題の記事

Android Tips #45 Dialog をフルカスタマイズする

2013.04.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

以前より社内で Dialog のデザイン変えたりレイアウト変えたりいろいろカスタマイズしたい!という要件を耳にすることが多いのでフルカスタマイズする方法を書き留めておきたいと思います。今回は例として下図のようなレイアウトの Dialog を作ってみたいと思います。

custom_dialog

DialogFragment をカスタマイズする

まず大前提として DialogFragment を継承したクラスでカスタマイズしましょう! Dialog を new して show するのはもう時代遅れです。Support Package を使えば Android 1.6 から使うことができますよ。

CustomDialogFragment.java

package jp.classmethod.android.sample.customdialog;

import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;

public class CustomDialogFragment extends DialogFragment {
    
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        
        Dialog dialog = new Dialog(getActivity());
        // タイトル非表示
        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        // フルスクリーン
        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
        dialog.setContentView(R.layout.dialog_custom);
        // 背景を透明にする
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        
        // OK ボタンのリスナ
        dialog.findViewById(R.id.positive_button).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        // Close ボタンのリスナ
        dialog.findViewById(R.id.close_button).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });
        
        return dialog;
    }

}

ポイントは3点、いずれも Dialog#getWindow() で Dialog が持っている Window インスタンスに対する設定です。
まず20行目の Window#requestFeature() でデフォルトのタイトルを消します。このメソッドは Dialog#setContentView() より先に呼ばなければいけないので注意してください。Window.FEATURE_NO_TITLE を渡すとタイトルが消えます。
次に22行目の Window#setFlags()WindowManager.LayoutParams.FLAG_FULLSCREEN を渡し、 Dialog をフルスクリーン表示にします。 最後に Window#setBackgroundDrawable() でデフォルトテーマに付いている影などを消します。
これでデフォルトテーマをかき消して自分が作った View だけ表示されるようになります!あとは自由自在にできますね。 OK ボタンや Close ボタンはすべてカスタムレイアウトに定義されていることとし、好きな処理を書いていきます。

おまけ

要点は以上になりますが、おまけとして今回作ったカスタムのレイアウトを載せておきます。Drawable も全部 XML で書いてみました。デザインを実装に落としこむときの参考までに。

dialog_custom.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- コンテンツ -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_below="@+id/title"
        android:layout_marginTop="6dp"
        android:layout_marginLeft="6dp"
        android:layout_marginRight="6dp"
        android:paddingBottom="20dp"
        android:background="@drawable/bg_dialog"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        >

        <!-- タイトル -->
        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_dialog_title"
            android:padding="10dp"
            android:text="Title"
            android:textSize="18sp"
            android:textColor="@android:color/white"
            />

        <!-- メッセージ -->
        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="20dp"
            android:lineSpacingExtra="6dp"
            android:text="MessageMessageMessageMessageMessageMessageMessageMessageMessage"
            android:textSize="16sp"
            android:textColor="#333333"
            />

        <!-- OK ボタン -->
        <Button
            android:id="@+id/positive_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="6dp"
            android:background="@drawable/bt_dialog_positive"
            android:text="OK"
            android:textColor="@android:color/white"
            />

    </LinearLayout>

    <!-- Close ボタン -->
    <Button
        android:id="@+id/close_button"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/bt_dialog_close"
        android:text="×"
        android:textColor="#9acd32"
        />

</RelativeLayout>

bg_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <corners android:radius="5dp"/>
    
    <stroke android:width="2dp" android:color="#9acd32"/>
    
    <gradient android:startColor="#ffffff" android:endColor="#dcdcdc" android:angle="90"/>

</shape>

背景は角丸矩形にグラデーションをほんわり付けてます。

bg_title.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    
    <corners android:topLeftRadius="5dp" android:topRightRadius="5dp"/>
    
    <solid android:color="#9acd32"/>

</shape>

タイトルの背景は右上と左上だけ角丸になるようにしています。

bt_dialog_positive.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <corners android:radius="5dp" />

    <solid android:color="#9acd32" />

</shape>

OK ボタンは普通の角丸矩形です。本来であれば selector を使うところですが省略してます。

bt_dialog_close.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    
    <solid android:color="@android:color/white"/>
    
    <stroke
        android:width="3dp"
        android:color="#9acd32"
        />
    
</shape>

Close ボタンは android:shape="oval" にすることで円を書いています。"×" は直接テキストにしているので、端末のフォントによってはデザインが変わってしまいますね…。

まとめ

「Dialog をこんなデザインにしたいからよろしく!」と急にふられたときもこれで安心ですね!