汎用的なIndicatorDialog

# 汎用的なIndicatorDialog

Androidには、`ProgressBar`という標準で備わっているIndicatorのコンポーネントが存在します。
ですが、今回は、カスタム化されたIndicatorを表示したいという人のための記事になります。

[参考] [ProgressBarについて](https://akira-watson.com/android/progressbar.html)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417396/9cf6f6f7-c0ec-46cb-b62e-8d1dc204a74b.png)

## 目次
1. 素材を用意
2. レイアウト作成
3. themes.xmlの修正
4. ImageUtilクラス作成
5. カスタムDialogFragmentの作成
6. 使い方(呼び出し方)
7. 補足

### 1. 素材を用意
まず、表示させるためのIndicatorを用意します。
以下のIndicatorを作成するサイトがあるので、GIFなどで用意します。
https://loading.io/

![progress_indicator.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417396/98238978-c617-3d1d-bcb8-6ab3e73ca81e.gif)

`progress_indicator.gif`というファイルを作成

### 2. レイアウト作成
`layout/indicator_layout.xml`を作成

```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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <ImageView
        android:id="@+id/progressImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="progress_image"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

### 3. themes.xmlの修正
`values/themes.xml`を修正

```xml
    <style name="Theme.IndicatorDialog" parent="Theme.MaterialComponents.Light.Dialog">
        <!-- タイトル非表示 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 透過させる -->
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>
```

### 4. ImageUtilクラス作成
`ImageUtil.kt`

```kotlin
object ImageUtil {
    @RequiresApi(Build.VERSION_CODES.P)
    @JvmStatic
    fun getGifAnimationDrawable(context: Context, fileName: String): AnimatedImageDrawable {
        val source = ImageDecoder.createSource(context.assets, fileName)
        return ImageDecoder.decodeDrawable(source) as? AnimatedImageDrawable
            ?: throw ClassCastException()
    }
}
```

### 5. カスタムDialogFragmentの作成
`IndicatorDialog.kt`を作成

```kotlin
class IndicatorDialog : DialogFragment() {
    @RequiresApi(Build.VERSION_CODES.P)
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        val view = inflater.inflate(R.layout.indicator_dialog, container, false)
        val imageView = view.findViewWithTag<ImageView>("progress_image")
        setImage(imageView)
        return view
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = Dialog(requireActivity(), R.style.Theme_IndicatorDialog)
        dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.window!!.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
        return dialog
    }

    @RequiresApi(Build.VERSION_CODES.P)
    fun setImage(imageView: ImageView) {
        val drawable = ImageUtil.getGifAnimationDrawable(requireContext(), "progress_indicator.gif")
        imageView.setImageDrawable(drawable)
        drawable?.start()
    }
}
```

### 6. 使い方(呼び出し方)
activityで呼ぶ場合

```kotlin
IndicatorDialog().show(supportFragmentManager, "indicator")
```

fragmentで呼ぶ場合

```kotlin
IndicatorDialog().show(parentFragmentManager, "indicator")
```

### 7. 補足

画面のタッチの有効/無効をしたい場合は、以下をセットしてください。

```kotlin
// 無効化
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)

// 無効化解除
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
```

また、通信終了時に解除したい場合などは、リスナーなどから上記をセットしてください。