スプラッシュ画面を作る (Splash Screen)

起動画面の役目としては、こんな感じでしょうか。

  1. ブランドロゴをレイアウト読み込みよりも早く表示させる
  2. 表示時間を調整できる
  3. 履歴に残さない
  4. バックボタンで戻れないようにしておく

目次

Android 8のwindowSplashscreenContentを使う

Android 8以降ならメインテーマにwindowSplashscreenContentを設定するだけでロゴを表示させられます。ロゴは自動的に消えるので、時間調整はできません。

<style name="AppTheme">
    <item name="android:windowSplashscreenContent">@drawable/launch</item>
</style>

Android 12のSplash Screenを使う

Android 12から起動時にアプリのアイコンが強制的に表示されるようになりました。12未満では表示されないので、同じようにアイコンを表示させたい場合はSplashScreenクラスを導入して、今までの起動画面を削除するなどの対応が必要になります。

(Googleの方針:デザインのガイドラインとして、ブランディング画像は使用しないことをおすすめします。)

起動画面のActivityを作る

drawable/launch.xmlを作る

通常のレイアウトでImageViewを表示させると遅いので、まずは、ロゴ画像のdrawableを作ります。背景色が無指定の場合は黒になります。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 背景色 -->
    <item android:drawable="@android:color/white" />

    <!-- ロゴ画像 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/logo_launch" />
    </item>

</layer-list>

ロゴ画像のbitmapは省略できます。

<item
    android:drawable="@drawable/logo_launch"
    android:gravity="center" />

ロゴ画像を専用のテーマにセットする

ここでnoHistoryを設定して履歴に残らないようにします。テーマはピリオドで継承しても良いですし、独立したものでも構いません。

<style name="AppTheme.Launch">
    <item name="android:windowBackground">@drawable/launch</item>
    <item name="android:noHistory">true</item>
</style>

AndroidManifestにLaunchActivityを追加してテーマを適用する

<activity
    android:name=".LaunchActivity"
    android:theme="@style/AppTheme.Launch">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>

 </activity>

LaunchActivity

レイアウトは使わないのでsetContentViewなし。

Android 12ではアイコンが表示されるので、ブランドロゴを表示させたくない場合はスキップ処理を追加します。onCreate内でfinish()すると、以降のonStart()、onStop()は呼ばれません。

/**
 *
 *  起動画面
 *
 *  起動ロゴはレイアウトにすると表示が遅れるので drawable を作ってテーマに設定する
 *
 *  起動ロゴを一定時間表示させてメイン画面への遷移を遅延させないと、アニメーションが省略される場合がある
 *  起動ロゴの表示中にアプリを閉じると勝手に開かれてしまうのでキャンセル処理も必要になる
 *
 *  メイン画面への遷移をフェードアニメーションにしたい場合は startActivity() の直後に overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
 *  メイン画面へ遷移後に finish() して戻るボタンで戻れないようにしておく
 *
 */
class LaunchActivity : AppCompatActivity() {

    private val startMainActivity = Runnable {
        val intent = Intent(this, MainActivity::class.java)
        startActivity(intent)
        finish()
    }

    private fun skipLaunching() {
        // If the app icon is displayed, skip launching the logo
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            startMainActivity.run()
        }
    }

    private fun startLaunching(duration: Long = 100) {
        window.decorView.postDelayed(startMainActivity, duration)
    }

    private fun cancelLaunching() {
        window.decorView.removeCallbacks(startMainActivity)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        skipLaunching()
    }

    override fun onStart() {
        super.onStart()
        startLaunching()
    }

    override fun onStop() {
        super.onStop()
        cancelLaunching()
    }
}

起動画面の存在意義

起動画面を作るのは手間がかかりますが、メイン画面の中に起動処理を書いてしまうと、画面構成を見直す時や、複数ヶ所での利用、レストア処理が必要になった時にとても困ります。起動画面からメイン画面へシームレスにアニメーションさせたい場合は共有トランジション※1も用意されていますので、起動画面は独立させておくのがオススメです。レイアウトが使えたら便利なんだけど。

※1、ActivityからFragmentへの異なる画面への共有トランジションはできません。