Zenn
🎨

【Android】Jetpack Composeで実現するSplash Screenカスタマイズ&初期化処理

2025/03/30に公開
1

概要

Androidアプリ開発で Jetpack Compose を使用している際、Splash Screen をどのように実装すれば良いかちゃんと調べられていなかったので、本記事では、Splash Screen の実装方法に加え、表示中に初期化処理を行う方法についても、実際に試した際の知見をもとにした記事になります。

スプラッシュ画面の設定

https://developer.android.com/develop/ui/views/launch/splash-screen?hl=ja

  • Android 12 以降では SplashScreen APIを使うようになった
  • SplashScreen API 互換性ライブラリを使用することもできる
  • スプラッシュ画面の仕組み
    • コールド スタート または ウォーム スタート 時にユーザーがアプリを起動
    • 定義したテーマとアニメーションを使用してスプラッシュ画面が表示
    • アプリの準備が整うと、スプラッシュ画面が閉じてアプリが表示

動作環境

  • Android Studio Ladybug | 2024.2.1 Patch 2
  • MBA M3 Sonoma 14.6.1
  • kotlin 2.1.0
  • compose-bom 2025.02.00

サンプルプロジェクトの作成

早速AndroidStudioを起動し、サンプルプロジェクトを作成していきます。

  • 「New Project」から「Empty Activity」を選択
    image1.png
  • プロジェクト名は「SplashSample」として以下内容で作成しました
    image2.png

作成時点でのSplash Screenは以下のように表示されます。

image3.gif

必要なパッケージのインストール

gradle/libs.versions.toml に以下を追加します。

[versions]
splashscreen = "1.0.1"

[libraries]
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashscreen" }

app/build.gradle.kts に以下を追加します。

dependencies {
  implementation(libs.androidx.core.splashscreen)
}

※ core-splashscreenの最新バージョンは👇で確認できます。

https://mvnrepository.com/artifact/androidx.core/core-splashscreen

Splash Screenの要素

image4.png

①: アプリアイコンはベクター型ドローアブルが推奨される

https://developer.android.com/develop/ui/views/graphics/vector-drawable-resources?hl=ja

  • ベクター型ドローアブルには以下2種類存在する
    • VectorDrawable
    • AnimatedVectorDrawable
  • ベクター型ドローアブル以外にもAdaptive Iconやその他の Drawable(BitmapDrawable など)も利用できるが推奨外
  • アニメーションの場合1,000 ミリ秒以下がおすすめ
  • デフォルトはランチャー アイコン
  • AdaptiveIconも使用できるが別途設定が必要だったりする

②: アイコン背景

  • 省略可能
  • AdaptiveIconを使用する場合、ウィンドウ背景とのコントラストが十分あれば、背景が表示される

③: アプリアイコンの外側 1/3 がマスクされる

④: ウィンドウ背景

背景色の変更

早速Splash Screenをカスタムしていこうと思います。まずは一番簡単そうな背景色の変更を試してみます

res/values/themes.xml が以下の様になっているかと思います。

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.SplashSample" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

上記を👇の様に修正します。

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.SplashSample" parent="Theme.SplashScreen">
        <item name="windowSplashScreenBackground">@color/purple_500</item>
        <item name="postSplashScreenTheme">@style/android:Theme.Material.Light.NoActionBar</item>
    </style>
</resources>

まずプロジェクト作成時に作られた Theme.SplashSample をそのまま使います。 parentTheme.SplashScreen に変更し、 postSplashScreenThemeTheme.SplashSampleparent に設定されていた値 ( android:Theme.Material.Light.NoActionBar ) を設定します。

最後に windowSplashScreenBackground で背景色を好きな色に設定します。

この時点でのSplash Screenは👇の様になります。

image5.gif

アイコンの変更

VectorDrawable

まずはアニメーション無しのVectorDrawableを試してみたいと思います。

早速👇を res/drawable/triangle_splash_icon.xml に保存します。

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="108dp"
    android:height="108dp"
    android:viewportWidth="108"
    android:viewportHeight="108">
    <path
        android:name="triangle"
        android:fillColor="#FF5722"
        android:pathData="M54,30 L78,78 H30 Z"/>
</vector>

👆ではSplash起動時にシステム側で中心部分を円にマスクして表示される為、30dpのpaddingを付けています。

image6.png

次に res/values/themes.xmlTheme.SplashSamplewindowSplashScreenAnimatedIcon を追加し、先ほど作成した triangle_splash_icon.xml を指定します。

    <style name="Theme.SplashSample" parent="Theme.SplashScreen">
        ...
        <!-- 以下を追加 -->
        <item name="windowSplashScreenAnimatedIcon">@drawable/triangle_splash_icon</item>
    </style>

※ この時に requires API level 31 で怒られる場合は、minSdkが31より低く設定されていると思うのでダイアログの Override Resource in values-v31 をクリックして res/values-v31/themes.xml を作成して下さい。

この時点でのSplash Screenは👇の様になります。

image7.gif

AnimatedVectorDrawable

次にアニメーションありのVectorDrawableを試してみたいと思います。

まずは今だとすぐにSplash Screenが閉じてしまうので、すぐに閉じないようにしたいと思います。

MainActivity.kt にすぐに閉じない様にdelayを設定してみます。

class MainActivity : ComponentActivity() {
    private var isReady = false // フラグ追加
    override fun onCreate(savedInstanceState: Bundle?) {
        // SplashScreen APIのinstallSplashScreenの戻り値を取得
        val splashScreen = installSplashScreen()
        // isReadyがtrueになるまで表示し続ける
        splashScreen.setKeepOnScreenCondition {
            !isReady
        }
        super.onCreate(savedInstanceState)
        // ...
        // フラグを数秒後にtrueに更新
        lifecycleScope.launch {
            delay(5000)  // 5秒待つ
            isReady = true
        }
    }
}

先ほど作成した res/drawable/triangle_splash_icon.xml にアニメーションを付けてみたいと思います。三角形の色を変化させるアニメーションを res/animator/splash_icon_animator.xml として以下の内容で作成します。

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:propertyName="fillColor"
    android:valueFrom="#FF5722"
    android:valueTo="#4CAF50"
    android:valueType="intType" />

次にAnimatedVectorDrawableを作成します。 res/drawable/animated_triangle_splash_icon.xml を以下の内容で作成します。

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/triangle_splash_icon">
    <target
        android:name="triangle"
        android:animation="@animator/splash_icon_animator" />
</animated-vector>

最後に res/values/themes.xmlwindowSplashScreenAnimatedIcon に作成した @drawable/animated_triangle_splash_icon を設定します。

    <style name="Theme.SplashSample" parent="Theme.SplashScreen">
        ...
        <!-- 以下を修正 -->
        <item name="windowSplashScreenAnimatedIcon">@drawable/animated_triangle_splash_icon</item>
    </style>

これでアプリ起動すると👇の様に色が変化されると思います。

image8.gif

終了アニメーションをカスタマイズする

SplashScreensetOnExitAnimationListener を使用して終了時のアニメーションを自分で定義する事もできます。

https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen#setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener)

MainActivity を以下の様に修正します。

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val splashScreen = installSplashScreen()
        // SplashScreenのアニメーションのカスタム
        splashScreen.setOnExitAnimationListener { splashScreenView ->
            // 5秒後にフェードアウト
            val fadeOut = ObjectAnimator.ofFloat(splashScreenView.view, View.ALPHA, 1f, 0f)
            fadeOut.duration = 5000L
            fadeOut.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    // アニメーション終了後にスプラッシュ画面を除去
                    splashScreenView.remove()
                }
            })
            fadeOut.start()
        }
        super.onCreate(savedInstanceState)

これでアプリ起動すると👇の様に5秒後にSplashScreenがフェードアウトしているのがわかります。

image9.gif

Splash Screen表示時に初期化処理などを行う

表示中に何か処理を行う場合に、Splash Screenを処理が完了するまで表示させる方法として以下の方法がある様です。

  1. SplashScreen API を使う
  2. OnPreDrawListener を利用して初回描画を遅延させる

SplashScreen API を使う

SplashScreensetKeepOnScreenCondition を使用して表示時間をコントロールします。

https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen#setKeepOnScreenCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition)

MainActivity を以下の様に修正します。

class MainActivity : ComponentActivity() {
    private var isReady = false
    override fun onCreate(savedInstanceState: Bundle?) {
        // 追加
        val splashScreen = installSplashScreen()
        splashScreen.setKeepOnScreenCondition {
            !isReady
        }
        
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            // ....
        }
        // 追加
        lifecycleScope.launch {
            delay(10000)  // 10秒待つ ※ここで初期化処理などを行う
            isReady = true
        }
    }
}

これでアプリ起動すると👇の様に10秒間表示されると思います。

image10.gif

OnPreDrawListener を利用して初回描画を遅延させる

ViewTreeObserverOnPreDrawListener を使用して初回描画を遅らせることができます。

https://developer.android.com/reference/android/view/ViewTreeObserver.OnPreDrawListener

MainActivity を以下の様に修正します。

class MainActivity : ComponentActivity() {
    private var isReady = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
          // ....
        }
        // ここから追加
        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(
            object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    return if (isReady) {
                        // 描画を終了させる
                        content.viewTreeObserver.removeOnPreDrawListener(this)
                        true
                    } else {
                        // isReady = falseの間は描画させる
                        false
                    }
                }
            }
        )
        lifecycleScope.launch {
            delay(10000)  // 10秒待つ ※ここで初期化処理などを行う
            isReady = true
        }
    }
}

これでアプリ起動するとこちらも同様に10秒間表示されると思います。

image11.gif

参考URL

https://developersancho.medium.com/jetpack-compose-splash-screen-api-36ca40c6196b

https://qiita.com/irgaly/items/7ebba96f16462158579d

https://zenn.dev/portinc/articles/port_android12_splash_screen

1

Discussion

ログインするとコメントできます