11
7

Androidの通知でアニメーションアイコンを表示する方法

Last updated at Posted at 2024-01-21

Androidの通知でアニメーションを表示できるのでしょうか?
できるとすればアイコンですよね。

AndroidのNotificationでは SmallIconLargeIcon の2種類のアイコンを設定できます。

val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(R.drawable.ic_android)
    .setLargeIcon(Icon.createWithResource(this, R.drawable.ic_android))
    .setContentTitle("Title")
    .setContentText("Text")
    .build()
notificationManager.notify(1, notification)

ステータスバーに表示されるのが SmallIcon

これは通知の先頭にも表示されます。LargeIconは通知の右側に表示されます。

SmallIcon/LargeIcon のアニメーション

SmallIconLargeIcon は指定方法が異なります。
SmallIcon は ResourceID もしくは IconCompat
LargeIconIcon もしくは Bitmap
Bitmapはアニメーション情報を持たせることはできませんが、 アニメーションリソースを ResourceID として指定したり、そこから作った Icon を渡すことはできます。

SmallIcon のアニメーションはAndroidユーザーのほとんどの方が見たことがあるはずです。
そのアイコンは、システムリソースに用意されていて、どのアプリからでも使えるようになっています。 android.R.drawable.stat_sys_download です。

これを指定してみましょう。

val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(android.R.drawable.stat_sys_download)
    .setLargeIcon(Icon.createWithResource(this, android.R.drawable.stat_sys_download))
    .setContentTitle("Title")
    .setContentText("Text")
    .build()

はい、ダウンロード中に表示されるアレですね。
これの実体は、 AnimationDrawable で以下のような定義になっています。
Drawableを複数枚つかったパラパラ漫画ですね。

<?xml version="1.0" encoding="utf-8"?>
<animation-list
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
    <item android:drawable="@drawable/stat_sys_download_anim0" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim1" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim2" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim3" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim4" android:duration="200" />
    <item android:drawable="@drawable/stat_sys_download_anim5" android:duration="200" />
</animation-list>

SmallIconLargeIconAnimationDrawable を指定することでアニメーションを表示させることができました。
また、 minSdk に注意が必要ですが、 AnimatedVectorDrawable を使うことも可能です。ただし、こちらの場合はループ再生はできないみたいです。

RemoteViews にアニメーションアイコンを表示させる

 Notification には RemoteViews を使ったカスタムViewを表示させることができます。

val remoteViews = RemoteViews(packageName, R.layout.notification)
val notification = NotificationCompat.Builder(this, channel.id)
    .setSmallIcon(R.drawable.ic_android)
    .setStyle(NotificationCompat.DecoratedCustomViewStyle())
    .setCustomContentView(remoteViews)
    .build()

RemoteViews は通常の View とは異なり、使用可能な View の種類が限定され、 View に対して行える操作も限定的になります。
以下のように複数の画像を表示させることはできますが

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

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/stat_sys_download"
        />
</LinearLayout>

アニメーション表示されません。
AnimationDrawable は ImageView に貼り付けただけではアニメーションされず、drawableの start() メソッドを呼び出す必要がありますが、 RemoteViews の仕組みではこのメソッドを実行することはできません。

では、どうするか?ですが、じつは、 RemoteViews に使える View で勝手にアニメーションしてくれる View があります。
ProgressBar です。

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

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

そして、 ProgressBar のクルクルアニメーションのリソースは android:indeterminateDrawable で別のアニメーションに差し替えることが可能です。

ということで、以下のようにレイアウトを作ると

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

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@android:drawable/stat_sys_download"
        />
</LinearLayout>

のような形で、自由度の高いレイアウトで、アニメーションを表示させることができます。


通知でのアニメーションは、下手に使うとユーザーに煩わしい印象を持たれてしまいマイナスになりかねませんので、ご利用は計画的に、よく考える必要があります。
ダウンロード中のアイコンのように短時間のステータス表示に使うとか、何か特別なイベントでの演出、のような工夫として使ってみるのであればありかもしれません。

以上です。

11
7
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
11
7