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

Compose for iOS for ZOZOTOWN

ねも
July 14, 2023

Compose for iOS for ZOZOTOWN

ねも

July 14, 2023
Tweet

Other Decks in Programming

Transcript

  1. Compose 

    for iOS 

    for ZOZOTOWN

    2023/07/11 ZOZO Tech Meetup - iOS/Android

    株式会社ZOZO

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android1ブロック

    財部彰太

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android2ブロック

    井上晃平


    Copyright © ZOZO, Inc.
    1

    View Slide

  2. © ZOZO, Inc.
    株式会社ZOZO

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 Android1ブロック

    財部 彰太

    食べる事が好きです。

    2

    View Slide

  3. © ZOZO, Inc.
    株式会社ZOZO

    ZOZOTOWN開発本部 ZOZOTOWNアプリ部 

    Android2ブロック

    井上 晃平

    最近はワンパンマンにハマっていて、ONE先生版と村田先
    生版の両方を読み返した


    温泉旅館にいくために、そろそろ自動車免許が欲しい

    3

    View Slide

  4. © ZOZO, Inc.
    アジェンダ

    1. 発表内容に関する注意と登壇の目的

    2. Compose for iOSの基礎知識

    2.1. JetBrainsが作るマルチプラットフォームの世界

    2.2. Compose for iOSとは

    2.3. レンダリング

    2.4. Compose for iOSの優れている点

    2.5. 今後注意したい動向

    3. ZOZOTOWNをCompose for iOSで作った
    3.1. 今回作ったもの
    3.2. カルーセル部分の作成
    3.3. スライダー部分の作成
    3.4. それ以外はハリボテです
    4. まとめ
    
 4

    View Slide

  5. © ZOZO, Inc.
    注意 

    Compose for iOSは2023年7月現在alpha版

    -> 今後大きな変更が加わる可能性がある


    目的

    すぐ仕事で使ってみてください!というよりは、今後の可能性をお伝えしたい。


    フィードバック窓口

    https://github.com/JetBrains/compose-multiplatform/issues


    1 発表内容に関する注意と登壇の目的



    KotlinConf’23 https://kotlinconf.com/talks/
    5

    View Slide

  6. © ZOZO, Inc.
    6
    Compose for iOSの基礎知識

    View Slide

  7. © ZOZO, Inc.
    7
    JetBrainsが作る

    マルチプラットフォームの世界

    View Slide

  8. © ZOZO, Inc.
    2.1 JetBrainsが作るマルチプラットフォームの世界

    ● Kotlin Multiplatform

    ○ 複数のプラットフォームでKotlinで書かれたコードを共有する技術

    ○ 2023年7月現在beta版であり、ドキュメントによるともうほぼstableとのこと


    ● Kotlin Multiplatform for mobile(KMM)

    ○ Kotlin Multiplatformのうち、モバイルに特化した場合の呼称

    ○ データ層のコードや、ViewModelなど、可能な限りの機能をKotlinで作成し、共有する

    ○ UIの記述はiOS/Android 各プラットフォームに任せている


    ● Compose Multiplatform

    ○ AndroidのUIを宣言的に作成できるJetpack Composeを用いて、Desktop, Web, Androidといったプラットフォー
    ムのUIを記述できるようにするための仕組み


    Kotlin Multiplatform https://kotlinlang.org/docs/multiplatform.html

    Compose Multiplatform https://www.jetbrains.com/ja-jp/lp/compose-multiplatform/


    8

    View Slide

  9. © ZOZO, Inc.
    9
    Compose for iOSとは

    View Slide

  10. © ZOZO, Inc.
    Compose MultiplatformのiOSへの対応がalpha版に!!

    Compose Multiplatform https://www.jetbrains.com/ja-jp/lp/compose-multiplatform/
    10
    Button(
    onClick = {
      //hogehoge
    }
    ) {
    Text("Hello $platform")
    }
    2.2 Compose for iOSとは


    View Slide

  11. © ZOZO, Inc.
    compose-multiplatform-ios-android-template https://github.com/JetBrains/compose-multiplatform-ios-android-template/#readme
    11
    2.2 Compose for iOSとは


    View Slide

  12. © ZOZO, Inc.
    2.2 Compose for iOSとは

    Compose Multiplatformと

    Kotlin Multiplatform for mobileを組み合わせることで、モバイ
    ルアプリ開発のネットワーク通信からUIの記述までの全範囲
    をKotlinで作成し、共有することが可能に!


    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/


    12

    View Slide

  13. © ZOZO, Inc.
    13
    レンダリング

    View Slide

  14. © ZOZO, Inc.
    2.3 レンダリング

    ● Android

    ○ 従来の形でレンダリングされる


    ● iOS

    ○ Skikoによってレンダリングされる

    ○ Skiko

    ■ SkiaをKotlin Multiplatformの中で使えるようにしたもの

    ○ Skia

    ■ Googleによって作成されたオープンソースの2Dグラフィックスライブラリ

    ■ Chrome、Android、Flutterなど様々なハードウェアやソフトウェアプラットフォームで動作する



    JetBrains/Skiko https://github.com/JetBrains/skiko

    Skia https://skia.org/

    Shader compilation jank https://docs.flutter.dev/perf/shader

    
 14

    View Slide

  15. © ZOZO, Inc.
    2.3 レンダリング

    ● FlutterはSkiaを使用した場合、レンダリングパフォーマンス上の課題が発生していた

    ○ Compose for iOSにおいても、Skiaを使用することによるレンダリングパフォーマンスの課題を持つのではない
    か


    ● KotlinConfの発表(25分あたり)でも、16msの画面の停止を観測したとの解説がある

    ○ 今後2msまで縮めていくとのこと

    15
    Compose Multiplatform on iOS by: Sebastian Aigner and Nikita Lipsky https://www.youtube.com/watch?v=FWVi4aV36d8
    Shader compilation jank https://docs.flutter.dev/perf/shader

    View Slide

  16. © ZOZO, Inc.
    16
    Compose for iOSの優れている点

    View Slide

  17. © ZOZO, Inc.
    2.4 優れている点① Jetpack ComposeのAPIがそのまま使える

    ● Android開発で用いるJetpack ComposeのAPIそ
    のものがiOSでも動作する


    ● 作成したComposableが無駄にならない


    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/
    17
    @Composable
    fun App() {
    MaterialTheme {
    var showImage by remember { mutableStateOf(false) }
    Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
    Button(onClick = {
    showImage = !showImage
    }) {
    Text("Toggle image")
    }
    AnimatedVisibility(showImage) {
    Image(
    painterResource("compose-multiplatform.xml"),
    "Compose Multiplatform Logo"
    }
    }
    }
    }
    import androidx.compose.animation.AnimatedVisibility
    import androidx.compose.foundation.Image
    import androidx.compose.foundation.layout.Column
    import androidx.compose.foundation.layout.fillMaxWidth
    import androidx.compose.material.Button
    import androidx.compose.material.MaterialTheme
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.remember
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.Alignment
    import androidx.compose.material.Text
    import androidx.compose.runtime.getValue
    import androidx.compose.runtime.setValue
    import org.jetbrains.compose.resources.ExperimentalResourceApi
    import org.jetbrains.compose.resources.painterResource

    View Slide

  18. © ZOZO, Inc.
    2.4 優れている点① Jetpack ComposeのAPIがそのまま使える

    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/
    18

    View Slide

  19. © ZOZO, Inc.
    2.4 優れている点② 相互運用性が高い

    ● UIKitView

    ○ iOS側の、地図、WebView、メディアプレイヤー、カメラといったプラットフォーム固有のウィジェットをComposeの
    なかに組み込むことができる



    ● ComposeUIViewController 

    ○ ComposeをSwift UIアプリケーションに埋め込むことができる

    →段階的な移行が可能に





    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/
    19

    View Slide

  20. © ZOZO, Inc.
    2.4 優れている点② 相互運用性が高い

    ComposeUIViewControllerを使うとiOSネイティブとの接続も簡単

    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/
    20
    @main
    struct iOSApp: App {
    var body: some Scene {
    WindowGroup {
    ZStack {
    Color.white.ignoresSafeArea(.all) // status bar color
    ContentView()
    }.preferredColorScheme(.light)
    }
    }
    }
    struct ContentView: View {
    var body: some View {
    ComposeView()
    .ignoresSafeArea(.all, edges: .bottom)
    }
    }
    struct ComposeView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
    Main_iosKt.MainViewController()
    }
    func updateUIViewController(_ uiViewController: UIViewController,
    context: Context) {}
    }
    iOSプロジェクト側(iosAppパッケージ)

    View Slide

  21. © ZOZO, Inc.
    fun MainViewController() = ComposeUIViewController { App() }
    @Composable
    fun App() {
    MaterialTheme {
    Screen()
    }
    }
    @Composable
    fun Screen() {
    // 実際のホーム画面を構成するコード
    }
    2.4 優れている点② 相互運用性が高い

    sharedモジュール/iosMainパッケージ sharedモジュール/commonMainパッケージ
    ComposeUIViewControllerが
    iOSネイティブとComposeを接続!!!
    compose-multiplatform-ios-android-template https://github.com/JetBrains/compose-multiplatform-ios-android-template/

    View Slide

  22. © ZOZO, Inc.
    22
    今後注意したい動向

    View Slide

  23. © ZOZO, Inc.
    2.5 今後注意したい動向 テーマ、デザインの方向性が未確定

    ● Compose for iOSはキャンバスベースのレンダリング

    ○ iOSとAndroidアプリケーションはどちらも同じように表示される

    ● 現状Compose Multiplatformは全てのプラットフォームでMaterialのウィジェットが適用されている

    ● ターゲットのプラットフォームの外観にUIを寄せていく仕組みを作るのか、統一的なUIにしていくかは未確定とのこ
    と



    => もしCompose for iOSがiOSへデザインを寄せずにAndroidライクなデザインのみを提供することになったら、Stable
    になっても導入は難しそう

    The Kotlin Blog https://blog.jetbrains.com/ja/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/
    23

    View Slide

  24. © ZOZO, Inc.
    24
    ZOZOTOWNをCompose for iOSで作った

    View Slide

  25. © ZOZO, Inc.
    25
    今回作ったもの

    View Slide

  26. © ZOZO, Inc.
    3.1 今回作った物

    Compose Multiplatformにより一つのコードで、iOSとAndroid版のホーム画面を作成

    26
    iOS版
 Android版


    View Slide

  27. © ZOZO, Inc.
    27
    動画だとこんな感じ


    View Slide

  28. © ZOZO, Inc.
    28

    ● カルーセルをスライドした時のテキストのアニメーションの部分



    ● 複雑なUIである、商品のGrid状のスライダー



    → 作れます。そう、Compose for iOSならね。

    実装上のポイント


    View Slide

  29. © ZOZO, Inc.
    29
    カルーセル部分の作成

    View Slide

  30. © ZOZO, Inc.
    3.2 カルーセル部分の作成

    ● HorizontalPagerを使用



    ● 要素のスライド時に、タイトルとサブテキストだけ

    アニメーション付きでスライドインする


    30

    View Slide

  31. © ZOZO, Inc.
    カルーセルの作成

    31
    ● HorizontalPagerで横方向のカルーセルを実装する。ページの
    設定、ページ間のマージン、ページの表示範囲等を引数で設定
    している。
    ● Android開発の時と同じ書き方でカルーセルを実装できる。
    @Composable
    fun Carousel(
    modifier: Modifier = Modifier,
    items: List,
    ) {
    val pagerState = rememberPagerState()
    Column(/* Columnの諸設定 */) {
    HorizontalPager(
    pageCount = items.size,
    state = pagerState,
    contentPadding = PaddingValues(horizontal = 20.dp),
    pageSpacing = 12.dp,
    ) { page ->
    CarouselItem(/* 後述します */)
    }
    // DotsIndicatorの実装
    }
    }

    View Slide

  32. © ZOZO, Inc.
    カルーセルの要素の作成 

    32
    ● BoxWithConstraintsでComposableの横幅を計測しつつ、要素を重ねるよ
    うに配置していく
    ● 引数で受け取ったpageOffsetFractionと、BoxWithConstraintsで計測した
    横幅で、カルーセルのスライド幅を算出している
    ● Modifier.graphicsLayerで、カルーセル自体 < タイトル < サブテキストの順
    番でスライドスピードが早くなるようなアニメーションを設定している
    @Composable
    fun CarouselItem(
    // その他の引数
    pageOffsetFraction: Float,
    ) {
    BoxWithConstraints(/* BoxWithConstraintsの諸設定 */) {
    val width = LocalDensity.current.run { constraints.maxWidth.toDp() }
    val pageOffset = width.value * pageOffsetFraction
    Image(/* カルーセルの画像 */)
    Column(/* タイトルとサブテキストを保持する Column */) {
    Text(
    modifier = Modifier
    .graphicsLayer {
    translationX = - pageOffset * 1.8f
    },
    // タイトルのその他の設定
    )
    Text(
    modifier = Modifier
    .graphicsLayer {
    translationX = - pageOffset * 2.2f
    },
    // サブテキストのその他の設定
    )
    }
    }
    }

    View Slide

  33. © ZOZO, Inc.
    33
    スライダー部分の作成

    View Slide

  34. © ZOZO, Inc.
    3.3 スライダー部分の作成

    34
    ● LazyHorizontalGridを使用
    ● GridCells.Fixedで2を設定することで、2行の横方
    向のスライダーを実現

    View Slide

  35. © ZOZO, Inc.
    スライダーの作成

    35
    ● 引数でrowFixedCountとして受け取った行数を、
    LazyHorizontalGridのrowsで渡す
    ● LazyHorizontalGridの内部で、SliderItemというスライダーの要
    素のコンポーザブルを配置する
    @Composable
    fun Slider(
    // その他引数
    sliderItemModels: List,
    rowFixedCount: Int,
    ) {
    Column(/* Column 設定 */) {
    Text(/* セクションのタイトル(アイテムランキング)表示 */)
    LazyHorizontalGrid(
    // Modifier設定
    rows = GridCells.Fixed(rowFixedCount),
    ) {
    sliderItemModels.forEachIndexed { index, model ->
    item {
    SliderItem(/* 後述します */)
    }
    }
    }
    }
    }

    View Slide

  36. © ZOZO, Inc.
    スライダーの要素の作成

    36
    ● SliderItemModelとして表示要素(ブランド名、値段、etc..)を受
    け取る
    ● RowとColumnを組み合わせた基本的なレイアウト
    @Composable
    fun SliderItem(
    model: SliderItemModel,
    // その他引数
    ) {
    Column(
    modifier = modifier.width(120.dp)
    ) {
    Image(/* 商品画像 */)
    Column(
    modifier = Modifier.fillMaxWidth()
    ) {
    Row(/* 1行目のブランド名の部分 */) {
    Text(/* Brand Name */)
    }
    Row(/* 2行目の値段とハートの部分 */) {
    Text(/* 値段 */)
    Image(/* ハート */)
    }
    }
    }
    }

    View Slide

  37. © ZOZO, Inc.
    37
    それ以外はハリボテです

    View Slide

  38. © ZOZO, Inc.
    3.4 それ以外はハリボテです

    38
    ● 実際に押せたり検索できたりはせず、見た目だけ作成
    ● Columnの内部のZOZOTOWNのロゴを保持しているRowで
    は、左端のSpacerと、通知とカートのアイコンを保持するRow
    にweight(1f)を指定することでZOZOTOWNのロゴで余った部
    分を等分している
    @Composable
    fun TopAppBar() {
    Column(
    modifier = Modifier
    .background(color = ZozoColor.GrayScaleFE)
    ) {
    Row(/* 設定 */) {
    Spacer(modifier = Modifier.weight(1f))
    Icon(/* ZOZOTOWNのロゴ */)
    Row(
    modifier = Modifier.weight(1f)
    ) {
    /* 通知とカートのアイコン */
    }
    }
    SearchBar(/* 検索バー */)
    TabLayout(/* すべて、シューズ、コスメのTabLayout */)
    }
    }

    View Slide

  39. © ZOZO, Inc.
    39
    ● これが画面に表示されるだけで、アプリのホーム画面がそ
    れっぽくなった
    ● シンプルにRowに画像を3つ載せている
    @Composable
    fun AttributeSelector(
    modifier: Modifier = Modifier
    ) {
    Row(
    modifier = modifier.padding(vertical = 12.dp)
    ) {
    Image(/* メンズ */)
    Image(/* レディース */)
    Image(/* キッズ */)
    }
    }
    メンズ、レディース、キッズの選択UI


    View Slide

  40. © ZOZO, Inc.
    40
    完成!!


    View Slide

  41. © ZOZO, Inc.
    41
    まとめ

    View Slide

  42. © ZOZO, Inc.
    まとめ

    ● KMMと合わせて、Kotlinエコシステムでアプリを作っていけるようになれば嬉しい。ワクワク。
    ● Swiftをほとんど書かず、Androidアプリを作ってる時と同じ感覚でiOSアプリを作れた。
    ● やっぱり両OSのコードを共通化できると嬉しい。
    ● カメラ等ネイティブの機能をふんだんに活用したりといったことは今回していないので、もしかしたら落とし穴はたくさんある
    かもしれない。

    Kotlin Multiplatform https://kotlinlang.org/docs/multiplatform.html


    42

    View Slide

  43. View Slide