Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jetpack Compose 完全に理解した

mkeeda
December 20, 2022

Jetpack Compose 完全に理解した

2019/11/26にサイボウズ社内で開催した勉強会の資料です。
Jetpack ComposeがまだStableになるずっと前の情報をまとめたものになります。

mkeeda

December 20, 2022
Tweet

More Decks by mkeeda

Other Decks in Programming

Transcript

  1. めっちゃええ感じ? Less Code Intuitive 💡 Accelerate Development 🚄 Powerful ⚡

    ~.xml は不要になり、Kotlin だけで UI を作成可能 UI を宣⾔するだけ。状態が変化すると UI は⾃動更新 既存のコードと完全に互換。Android Studio がライブプレビュー Material Design, ダークテーマ, アニメーションなどをサポート 4
  2. Jetpack = Unbundle なツールキット🚀 • Android は OS アップデートの普及が遅い 😨

    • Android 9.0 のシェア: 10.4 % • iOS 13 のシェア: 50 % • OS バージョンに依存する API は中々使われない 🤢 • 新しい API を OS アップデートに含めて配布しても使われない 🤮 • Support library → Jetpack 8
  3. 今までの “UI を構成する” 11 1. データが与えられたとき、何を表⽰するか 2. イベントに対して何をするか 3. UI

    は時間経過でどのように変化すべきか 4. レイアウトの定義 (my_fragment.xml, attrs.xml, styles.xml )
  4. 命令型プログラミングで時系列を記述する⾟さ 13 99+ 10 fun updateCount(count: Int) { if (count

    == 0) { removeBadge() } else if (count <= 99 && hasBadge()) { setBadgeText(count) } else if ... }
  5. Jetpack Compose の “UI を構成する” 14 1. データが与えられたとき、何を表⽰するか 2. イベントに対して何をするか

    3. UI は時間経過でどのように変化すべきか 4. レイアウトの定義 (my_fragment.xml, attrs.xml, styles.xml )
  6. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContent { Greeting("Ippei") } } } @Composable fun Greeting(name: String) { Text("Hello $name") } UI を表⽰する 16
  7. UI は関数の組み合わせで構成する • @Composable をつける • Composable 関数は
 データを UI

    に変換する • データは引数として受け取る • Composable 関数は 
 Composable 関数を呼び出せる 17 @Composable fun Greeting(name: String) { Text("Hello $name") }
  8. @Composable fun Greeting(name: String) { if (name == "Ippei") {

    Text("Hello $name") } else { Text(text = "You are not Ippei") } } @Composable fun Greeting(names: List<String>) { for (name in names) { Text("Hello $name") } } 18
  9. 19

  10. @Composable fun NewsStory(newsItem: NewsItem) { val image = +imageResource(newsItem.imageId) Card(elevation

    = 2.dp, shape = RoundedCornerShape(4.dp)) { Column(crossAxisSize = LayoutSize.Expand) { Container(expanded = true, height = 180.dp) { DrawImage(image = image) } Column(modifier = Spacing(16.dp)) { Text(text = newsItem.title, maxLines = 2, overflow = TextOverflow.Ellipsis, style = (+themeTextStyle { h6 }).withOpacity(0.87f)) Text(text = newsItem.author, style = (+themeTextStyle { body2 }).withOpacity(0.87f)) } } } } 20
  11. • ViewModel, LiveData, Rx, Coroutines + Flow • View が

    ViewModel のデータを継続して購読する 22 Data View (UI) Reactive programming ViewModel Data
  12. @Model data class LikeButtonState( var count: Int = 0 )

    @Composable fun LikeButton( state: LikeButtonState = LikeButtonState() ) { Button( text = "${state.count} Like", onClick = { state.count++ } ) } @Model で状態管理 24
  13. android.widget.CheckBox 27 // CheckBox ͸ CompoundButton ͷαϒΫϥε (Java) public abstract

    class CompoundButton extends Button implements Checkable { private static final String LOG_TAG = CompoundButton.class.getSimpleName(); private boolean mChecked; … // Activity or Fragment (Kotlin) checkBox.setOnCheckedChangeListener { checkBox, isChecked -> // After changed ... checkBox.isChecked = true }
  14. android.widget 😩 28 誰が View のイベントに反応する? 誰が状態を所有してる? 誰が状態を更新する? View ではない

    Listener を実装した誰か 1つの View の状態を複数箇所で所有可能 基本的に View ⾃⾝が更新するが、誰でも更新可能
  15. Single source of truth 29 誰が View のイベントに反応する? 誰が状態を所有してる? 誰が状態を更新する?

    状態の所有者がイベントに反応する。 状態の所有者は常に1つ。 状態の所有者のみが更新する。
  16. Single source of truth in Compose 30 @Model class FormState(var

    optionChecked: Boolean = false) @Composable fun Form(formState: FormState = FormState()) { Checkbox( checked = formState.optionChecked, onCheckedChange = { newState -> formState.optionChecked = newState } ) } ※ CheckBox の⽂⾔は別途 Text で表⽰する必要がある
  17. データの流れは⼀⽅向 32 NewsContent NewsCard NewsCard NewsCard Image Text Image Text

    Image Text Business Logics User Data Events ▪ = Composable
  18. @Composable fun NewsContent(newsItems: List<NewsItem>) { newsItems.forEach { newsItem -> NewsCard(newsItem)

    } } @Composable fun NewsCard(newsItem: NewsItem) { Column { SimpleImage( image = +imageResource(newsItem.imageId) ) Text(text = newsItem.title) } } データはトップダウンに伝搬 • 引数で渡す • 親 → ⼦ へ伝搬 • グローバル変数を参照しない 33
  19. 35 @Composable fun NewsContent( newsItems: List<NewsItem>, newsState: NewsState = NewsState()

    // Model ) { Column { TopAppBar(title = { Text(text = newsState.selectedNewsTitle ?: "not selected") }) newsItems.forEach { newsItem -> NewsCard( newsItem = newsItem, onClick = { newsState.selectedNewsTitle = newsItem.title } ) } } } @Composable fun NewsCard(newsItem: NewsItem, onClick: () -> Unit) { Clickable(onClick = onClick) { // Image ͱ Text } } ※ スタイルは調整してあります
  20. Composable → View 変換 (予定) 37 What's New in Jetpack

    Compose (Android Dev Summit ’19) のスライドより
  21. Composable 内で View を使う 38 • ⾃作したコンポーネントや外部ライブラリとの共存させたい • ViewBinding ?

    • 既存の View をラップした Composable を⽤意する? • 既存の View は Single source of truth の設計ではない問題
  22. 🚀 Jetpack Compose ⚒ 39 1. Unbundle な UI ツールキットの提供

    2. 宣⾔的な記述による UI 時系列の気配りからの解放 3. 簡潔な状態管理とイベントハンドリングの実現 4. Kotlin の⾔語機能をフルに使ったレイアウト ※ Technical Preview なのでプロダクトにはまだ使えない
  23. Jetpack Compose の正体 🔍 40 UIツールライブラリ Composable 関数, Material Theme,

    etc Kotlin コンパイラプラグイン @Composable, @Model からのコード⽣成 +
  24. その他 • Layout • Effects & memo • Theme •

    気になる⼈は Codelab を⾒てね!
 https://codelabs.developers.google.com/codelabs/jetpack-compose-basics/#0 41