Compose Multiplatform でプラットフォーム固有のコンポーネントを表示する

2024.06.15

前回の記事で、Compose Multiplatformを使って起動画面からホーム画面への画面遷移を実装した。詳細は以下の記事を参照して欲しい。

Compose Multiplatformとは

Compose Multiplatform(CMP)は、Kotlinを使ってAndroidとiOSの両方に対応したUIを構築するためのライブラリだ。同じコードベースから両方のプラットフォームに対応したアプリケーションを作成できる。CMPプロジェクトの作成方法やエミュレータでの実行方法については、以下の記事で詳しく紹介している。

開発環境

  • MacBook Pro (16インチ, 2021)
  • macOS Sonoma 14.5
  • Xcode 15.4
  • Android Studio Jellyfish | 2023.3.1 Patch 2

プラットフォームの世界観を守るために

以下の図のように、起動画面で実装したマテリアルデザインのインジケーターは、そのままiOSアプリとしてリリースするとユーザーに違和感を与える可能性がある。多くのユーザーにとって些事かもしれないが、私はiOSの世界観を守りたいと考えている。

Expected and actual declarationsの機能を使うと、iOSとAndroidそれぞれのプラットフォーム固有の実装ができる。この記事では、この機能を利用してプラットフォームに応じたUIコンポーネントの切り替え方法を紹介する。

外部ライブラリを追加する

前述の通り、Compose Multiplatformには標準でAndroid風のマテリアルデザインのコンポーネントが提供されているが、iOS風のコンポーネントは標準で用意されていない。そこで、alexzhirkevich/compose-cupertinoという外部ライブラリを利用する。

まずは、build.gradle.ktsファイルに以下の依存関係を追加する。

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("io.github.alexzhirkevich:cupertino:0.1.0-alpha04") // <--- Add
            implementation("io.github.alexzhirkevich:cupertino-adaptive:0.1.0-alpha04") // <--- Add
        }
    }
}

ファイルを追加する

Kotlin Multiplatformでは、expectactualキーワードを使用して、プラットフォームごとの具体的な実装を提供できる。これにより、共通のコードをプラットフォームに依存しない形で書き、特定のプラットフォームに特有の実装を提供できる。それぞれのファイルの実装を見ていこう。

まず、expectactualを実装するファイルを追加する。commonMainProgressIndicator.ktiosMainProgressIndicator.ios.ktandroidMainProgressIndicator.android.ktを追加する。

expect キーワード

expectキーワードは共通コードで宣言され、特定のプラットフォームで実装されることを期待する宣言だ。共通モジュール(commonMain)で定義され、ここでは実際のViewを実装しない。

import androidx.compose.runtime.Composable

@Composable
expect fun ProgressIndicator()

actual キーワード

actualキーワードは、expect宣言に対する具体的なプラットフォーム固有の実装を提供するために使用される。これは、各プラットフォームモジュール(androidMainやiosMainなど)で定義される。

androidMainのProgressIndicatorでは、CircularProgressIndicatorを利用する。

import androidx.compose.material.CircularProgressIndicator
import androidx.compose.runtime.Composable

@Composable
actual fun ProgressIndicator() {
    CircularProgressIndicator()
}

最後に、iosMainのProgressIndicatorでは、導入したライブラリのCupertinoActivityIndicatorを利用する。

import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import io.github.alexzhirkevich.cupertino.CupertinoActivityIndicator
import io.github.alexzhirkevich.cupertino.ExperimentalCupertinoApi

@OptIn(ExperimentalCupertinoApi::class)
@Composable
actual fun ProgressIndicator() {
    CupertinoActivityIndicator(
        size = 24.dp,
    )
}

iOSシミュレータで実行すると、下図のようにiOSではUIActivityIndicatorView風のインジケーターが表示されるようになった。

以上の手順で、Compose Multiplatformを使ってiOSスタイルのプログレスインジケーターを実装できた。これでiOSアプリを使っているユーザーが違和感を感じなければ嬉しい。

関連記事