UI Layer(Jetpack Compose)
2024/10/31
Android Studio の新規プロジェクト作成で作るか、archtecture-templates/base を元にするのがよい。
View ベースアプリの場合は GUI で XML ファイルを更新することができたが Composable 関数の場合にはそれが無い。
Composable関数
レイアウト
Columnなどを組み合わせる。
これらも Composable 関数なのでText
などの部品と組み合わせることができる。
- androidx.compose.foundation.layout
- よく使う関数:
Box
,Column
,Row
,Spacer
- よく使う関数:
レイアウトは難しい。
あまりにうまく行かない場合は、画像でレイアウトを作って Gemini などにサンプルコードを書いてもらうと良いだろう。
ちなみにブラウザで日本語表示にしているとメニューに「ポケベル」という項目があるが、 これは “pager(無線呼び出し - wikipedia)” を直訳したものである。
部品
これを書いている時点ではマテリアルデザイン3(M3 と略されることもある)である。
Text
のような基本部品はマテリアルデザインのバージョンごとに定義されているので注意しよう
(
M2のText
,
M3のText
)。
androidx.compose.material3
は M3、数字が付かない androidx.compose.material
は M2 である。
- androidx.compose.material3
- よく使う関数:
Button
,Card
,Text
MaterialTheme
,Scaffold
,Surface
- (ドキュメントのページが重たい)
- よく使う関数:
Image
は別のパッケージである。
- androidx.compose.foundation
- よく使う関数:
Image
- よく使う関数:
Modifier
だいたいの Composable関数で引数に指定できる Modifier
は調整に使う。
同じModifier
でも指定する関数によってパラメータにできないものもある。
また、Modifier
でも Composable関数でも同じような設定ができるものもある。
一概にどちらがどうということは言えないので、必要になったときに調べると良いだろう。
テーマ
新規プロジェクトで作成した場合、ui/theme/Theme.kt
にプロジェクト名Theme
という Composable関数 が作られている。
デフォルトではダイナミックカラーが有効になっているので、実機で動作させるとエミュレータと色が異なるかもしれない。
ダイナミックカラーを無効にしたり実機が未対応だったりするとデフォルト(baseline)のテーマで表示される。
アプリでのテーマを組み込むこともできる。
自作するのは大変なのでいくつかテーマを作ってくれるサイトがある。
アプリ名がないためTheme.kt
のテーマ定義名が違っているくらいである。
Codelabs では Surface
を使う例が多い。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent {
AppTheme {
Surface(modifier = Modifier.fillMaxSize()) {
MainScreen()
}
}
}
}
}
Android Studio でアプリを作ると Scaffold が使われている。
topBar
とbottomBar
を実装できるので、それだけで普通のアプリの見た目になる。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MainScreen(modifier = Modifier.padding(innerPadding))
}
}
}
}
}
Preview
Composable関数は Android Studio でプレビュー画面を見ることができる。
@Preview
のパラメータで調整もできる。
いくつかの Composable関数を組み合わせて 1つの画面にすることもあるので、 それぞれをプレビューで
画面遷移
画面の遷移もアプリ内とアプリ外があるが、ここではアプリ内について記載する。
- ナビゲーションの原則 - Android Developers
- ナビゲーション - Android Developers
- Compose で画面間を移動する - Codelabs
- アプリ内の遷移
- 別アプリへの遷移(
Intent
)
概要
ここでは画面遷移を固定で実装しておく方式について概要を記載する。
Android Studio でプロジェクトを作った場合は画面遷移のコードはない。
architecture-templates を使った場合は NavHost()
は用意してあるが画面が 1枚しかないので遷移しない。
codelabsで一通りやって見るのがよいと思う。
- ライブラリを組み込む
- 画面遷移用の Composable関数を用意する
- 画面名と対応する Composable関数を決めておく
NavHost()
に、画面名と Composable関数の呼び出し方を定義する(composable()
)
- Main Activity で呼び出すのは画面の Composable関数ではなく画面遷移の Composable関数に変更する
- 遷移は
rememberNavController()
のインスタンスを使う.navigate(画面名)
: 指定した画面に遷移.popBackStack()
: 戻る
画面遷移をするのにrememberNavController()
のインスタンスがいるので、
それをどこで持ってどうするのがよいのかがまだよくわかっていない(2024/10/30現在)。
architecture-samples では画面の Composable関数にボタン押下イベント関数として渡しているようだ。
依存するものは引数に取る
ボタン押下などのイベントが発生したときに実行する内容は直接実装せず、
自作 Composable関数の引数でもらうようにしておくと良い。
そうするとテストするときにやりやすくなる。
また、状態についても UI elements では持たないようにする。
そうすると UI elements としてはステートレスにすることができる。
- 状態ホイスティング(hoist, hoisting)
ViewModel
UI elements がステートレスになった分、ViewModel がステートフルになるという感じか。
概念的な ViewModel があるのかもしれないが、 少なくとも Android アプリでは androidx.lifecycle.ViewModelクラスを継承する。
UI 状態生成パイプラインやAndroid アーキテクチャに関する推奨事項を見るとビジネスロジックを UI Layer に置いてもよさそうではあるが、 アプリの推奨アーキテクチャ でビジネスロジックは Data Layer 側であることを書いているのでその方がよいだろう。
UI state
UI elements で表示するのに使うデータは data class
にまとめておき、ViewModel でインスタンスを生成して持っておく。
データを提供する場合はインスタンスそのものではなく、その Read Only 版を提供するようにしておく。
具体的には Kotlin の MutableStateFlow
でインスタンスを作り、.asStateFlow()
で Read Only 版を提供する。
Read Only 版はプロパティとして提供するのが普通なようだ。
State
系のインスタンスを UI elements が描画に使っていると、
インスタンスに更新が行われたときに自動で再composeが行われて描画に反映されるしくみになっている。
更新はMutableStateFlow
のインスタンスを .update{ it.copy(...) }
のように実行する。