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

catch
100件のシェア(ちょっぴり話題の記事)

この記事は公開されてから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 をこんなデザインにしたいからよろしく!」と急にふられたときもこれで安心ですね!

AWS Cloud Roadshow 2017 福岡

  • 平井 諒

    自前のプロジェクトに取り込む際に、themeにnumberPickerStyleを指定しそこねて少しハマったのでそこについても触れておくと良いかもしれないです。

    @style/NPWidget.Holo.NumberPicker

    @style/NPWidget.Holo.Light.NumberPicker

    • suwa.yuki

      コメントいただきありがとうございます!
      返信が遅れてしまい大変申し訳ありませんでした。

      こちらのコメントは以下のブログに関するコメントでしょうか?
      https://dev.classmethod.jp/smartphone/android/android-tips-number-picker-lib/
      ご指摘ありがとうございます。参考にさせていただきます。

      • 平井 諒

        そちらの記事にコメントしたつもりでいました・・・なぜこの記事に・・・
        参考にしていただければ幸いです

  • おしいな

    誤字、脱字が多すぎて使えませんな!

    • suwa.yuki

      ご指摘いただきまして誠にありがとうございます。
      改めて本記事をレビューいたしましたが、誤字・脱字が見つけられませんでした。
      お手数ではございますが、誤字・脱字している箇所もご指摘いただけると幸いです。

  • 武藤 小田

    誤字ってCustomDialog.javaのclass名がCustomDialogFragmentってことかな?

    • suwa.yuki

      コメントいただきましてありがとうございます!
      ご指摘いただいたとおり一部ファイル名に誤りがありましたので、修正させていただきました。
      以前確認した際に見つけられなかった箇所だったので、非常に助かりました。ありがとうございました!

  • yoko

    こうしたらこうなる、というように書けないですか?

    • suwa.yuki

      コメントいただき、ありがとうございます!

      ダイアログを表示した後、何か動作を行わせたいということでしょうか?
      ダイアログに表示されている「OK」または「×」をタップした時の動作は
      記事の中にある CustomDialogFragment.java のコードの中にある
      「OK ボタンのリスナ」または「Closeボタンのリスナ」に記述することができます。
      「dismiss();」と書いてある部分です。

      ぜひ、お試しください!

  • けんけん

    「Dialog を new して show するのはもう時代遅れです。」つまりは、どう呼べば良いってこと?

    • suwa.yuki

      コメントいただき、ありがとうございます!

      こちらですが、以前は Dialog クラスを使って作る方法が一般的でしたが
      現在は DialogFragment クラスを使うことが推奨されています。

      DialogFragment クラスのインスタンスを Activity などから生成し、
      このインスタンスの show メソッドを呼ぶようにします。

      つまり、Activity からは Dialog クラスを直接使うのではなく
      DialogFragment クラスを使いましょう、ということを述べておりました。

      詳しくは公式のドキュメントに記載されていますので、ご参照いただければと思います。

      DialogFragment | Android Developers
      http://developer.android.com/reference/android/app/DialogFragment.html

      • けんけん

        返信ありがとうございます。
        何だか、すみません。
        Androidアプリを開発するのは久しぶりで何かと戸惑っています。

        色々と参考にさせていただいています。
        これからも、よろしくお願いします。

        • suwa.yuki

          いえいえ、貴重なご意見ありがとうございました!
          当ブログが少しでも開発のお役に立てれば幸いです。
          今後ともよろしくお願い致します。