📱

Android:Dialogのデザインをカスタムして表示する

2022/10/06に公開

はじめに

AnalogDialogでDialogを狙ったデザインにしようとしましたが、ボタンの位置の細かい調整など融通がききませんでした。それなら最初からDialogのLayoutをつくって、表示させたほうが手戻りが少なくなりそうです。
そのDialogのlayoutをカスタムする方法を書き残します。

やりかた

Activityについて

サンプルコードは、Activityにはボタンが1つ設置してありそれを押すとダイアログが表示されます。

MainActivity.kt
MainActivity.xml
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setTitle("Dialog Test")

        val displayDialog = findViewById<Button>(R.id.button)

        displayDialog.setOnClickListener{
            val dialog = CustomDialog()
            val manager: FragmentManager = supportFragmentManager
            dialog.show(manager, "simple")
        }
    }
}

activity_main.xml
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Dialog"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

ダイアログについて

ダイアログはDialogFragmentを使用します。
Dialogはカスタムしたlayoutをxmlファイルで記述して使用します。

custom_dialog.xml
custom_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/custom_dialog"
        android:layout_width="600dp"
        android:layout_height="320dp"
        android:background="@drawable/dialog_design"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:id="@+id/dialogTitle"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@drawable/dialog_design_titlebar"
            android:gravity="center"
            android:text="test"
            android:textColor="@color/white"
            android:textSize="@dimen/dialog_title_text_size"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/dialogMessage"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:layout_marginStart="20dp"
            android:layout_marginTop="20dp"
            android:layout_marginEnd="20dp"
            android:text="テスト"
            android:gravity="center"
            android:textColor="@color/black"
            android:textSize="@dimen/dialog_message_text_size"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dialogTitle" />

        <Button
            android:id="@+id/dialogButtonPositive"
            android:layout_width="150dp"
            android:layout_height="60dp"
            android:layout_gravity="center_vertical"
            android:layout_marginTop="20dp"
            android:layout_marginEnd="60dp"
            android:backgroundTint="#00BCD4"
            android:gravity="center"
            android:text="はい"
            android:textColor="@color/white"
            android:textSize="@dimen/dialog_message_text_size"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dialogMessage"
            app:layout_constraintVertical_bias="0.0" />

        <Button
            android:id="@+id/dialogButtonNegative"
            android:layout_width="150dp"
            android:layout_height="60dp"
            android:layout_gravity="center_vertical"
            android:layout_marginStart="60dp"
            android:layout_marginTop="20dp"
            android:backgroundTint="#00BCD4"
            android:gravity="center"
            android:text="いいえ"
            android:textColor="@color/white"
            android:textSize="@dimen/dialog_message_text_size"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/dialogMessage"
            app:layout_constraintVertical_bias="0.0" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

そして、下記のようにDialogFragmentを記述します。

Dialog.kt
Dialog.kt
class CustomDialog: DialogFragment(){
    private lateinit var dTitle: String
    private lateinit var dMessage: String
    private lateinit var dButtonPositive: String
    private lateinit var dButtonNegative: String

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val dialog = Dialog(requireContext())

        // ダイアログを透過状態に変更
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        // カスタムしたレイアウトをわたす
        dialog.setContentView(R.layout.custom_dialog)

        val dialogTitle = dialog.findViewById<TextView>(R.id.dialogTitle)
        val dialogMessage = dialog.findViewById<TextView>(R.id.dialogMessage)
        val dialogButtomPositive = dialog.findViewById<Button>(R.id.dialogButtonPositive)
        val dialogButtomNegative = dialog.findViewById<Button>(R.id.dialogButtonNegative)

        dTitle = "タイトルを表示"
        dMessage = "テキストを表示"
        dButtonPositive = "はい"
        dButtonNegative = "いいえ"

        dialogTitle.setText(dTitle)
        dialogMessage.setText(dMessage)
        dialogButtomPositive.setText(dButtonPositive)
        dialogButtomNegative.setText(dButtonNegative)

        dialogButtomPositive.setOnClickListener {
            // 処理を記述
            dialog.dismiss()
        }
        dialogButtomNegative.setOnClickListener {
            // 処理を記述
            dialog.dismiss()
        }

        // ダイアログのタップを無効にする場合、下記のコメントアウトを外す
        // dialog.setCanceledOnTouchOutside(false)
        return dialog
    }
}

このとき、さきほどつくったlayoutをsetContentViewでわたすことで、自分で作成したlayoutのダイアログをつくることができます。

dialog.setContentView(R.layout.custom_dialog)

そして、それぞれのパーツをfindViewByIdでみつけ、setTextすることで文言を変更できます。またsetOnClickListenerをつかってボタンをおしたときの処理を記述できます。

その他のパラメータ

文字サイズやダイアログに使用する色はres/values直下にdimens.xmlやcolors.xmlに記述し管理すると、他のダイアログをつくったときにパラメータを共通化できるので便利です。今回のサンプルコードでは下記のように指定しています。

dimens.xml
dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="button_text_size">24sp</dimen>
    <dimen name="dialog_title_text_size">34sp</dimen>
    <dimen name="dialog_message_text_size">24sp</dimen>
    <dimen name="dialog_corner_radius">10dp</dimen>
</resources>

ダイアログを角丸にする

ダイアログはそのままだと、直角形の形状です。
角丸にするには、res/drawable直下に下記のようにファイルをつくって、形状を記述します。

dialog_design.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <corners
                android:topRightRadius="@dimen/dialog_corner_radius"
                android:bottomRightRadius="@dimen/dialog_corner_radius"
                android:bottomLeftRadius="@dimen/dialog_corner_radius"
                android:topLeftRadius="@dimen/dialog_corner_radius"
                />
            <solid android:color="@color/white" />
        </shape>
    </item>
</selector>
dialog_design.titlebar.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <corners
                android:topRightRadius="@dimen/dialog_corner_radius"
                android:topLeftRadius="@dimen/dialog_corner_radius"
                />
            <solid android:color="#00BCD4" />
        </shape>
    </item>
</selector>

それをダイアログのxmlファイルで呼び出します。

custom_dialog.xml
android:background="@drawable/dialog_design"
custom_dialog.xml
android:background="@drawable/dialog_design_titlebar"

角丸の指定を2つのファイルに分けている理由は、今回作成したダイアログはタイトルを表示する部分(上部の色を塗りつぶして白抜きにした部分)とメッセージを表示する部分(白い背景色の部分)の2つのパーツが重なっているためです。
そのためタイトルを表示する部分は上の左右を角丸にして、さらにメッセージを表示する部分は4隅を角丸にすることで、全体を角丸のダイアログになるよう実現しています。

終わりに

一度理解してしまえば、ダイアログをカスタムしやすいかと思います。

Discussion