比較して覚える SwiftUIとJetpack Compose

# はじめに
この記事は[クラスター Advent Calendar 2022 の 13日目](https://qiita.com/advent-calendar/2022/cluster)の記事です。
前回の記事はmillioさんの[EMの転職活動（入社エントリーを添えて）](https://note.com/nktn_milio/n/n0d89f10e9ed8)でした。元々EMをやっていてエンジニアとしてクラスターに入られてる方って意外と多そうですね！（自分もそうです）


# SwiftUIとJetpack Composeの比較
クラスターでは複数領域を担当しているエンジニアもいて、iOS/Unityを見てる方や、Web/Androidを見てる方など様々です。EMからの提案もあって自分も最近iOS/Android両方やるマン（見習い）にジョブチェンしました。

ここ数年はiOSエンジニアとして働いていたのでiOSについては大体わかってるつもりなのですが、Androidに関しては実務で画面開発した経験はほぼありませんでした。幸いにもclusterのandroidアプリはCompose対応されている画面が多いため、SwiftUIとの比較で考えて実装していくことでスムーズにレイアウトを組むことができました。
それぞれ実装する場合どのようになるか、簡単な例をいくつか挙げてみます。

### 縦に並べる
- SwiftUI
```swift
struct ScoreBoard: View {
    var body: some View {
        VStack {
            Text("Taro")
            Text("100")
        }
    }
}
```

-  Compose
```kotlin
@Composable
fun ScoreBoard() {
    Column {
        Text("Taro")
        Text("100")
    }
}
```

### 横に並べる
- SwiftUI
```swift
struct ScoreBoard: View {
    var body: some View {
        HStack {
            Image("~~~")

            VStack {
                Text("Taro")
                Text("100")
            }
        }
    }
}
```

- Compose
```kotlin
@Composable
fun ScoreBoard() {
    Row {
        Image("~~~")

        Column {
            Text("Taro")
            Text("100")
        }
    }
}
```

### タップイベントを追加する
- SwiftUI
```swift
struct ScoreBoard: View {
    var body: some View {
        VStack {
            Text("Taro")
            Text("100")
        }
        .onTapGesture { /* impl: tapEvent */ }
    }
}
```

- Compose
```kotlin
@Composable
fun ScoreBoard() {
    Column(
        Modifier.clickable(onClick = { /* impl: tapEvent */ })
    ) {
        Text("Taro")
        Text("100")
    }
}
```

Viewの修飾やイベント追加に関しては、SwiftUIはメソッドチェーン、ComposeはModifierという違いはありますが似たような感覚で書けますね。


## Previewの活用
ところで自分はRowとColumnどっちが縦でかどっちが横か一生覚えられないマンなのですが、そんな時便利なのがPreview機能です。
SwiftUI/Compose共にPreview機能があり、実装中のレイアウトを確認しながら開発を進めることができます。
表示する値のパターンをいくつか用意して表示崩れがないか確認するのが基本ですが、それぞれに便利な機能もあります。こういう機能探して活用していくの好きです。

### SwiftUI編
- デフォルトではデバイスのフレーム内にプレビューを表示しますが、`.previewLayout(.sizeThatFits)`を使うと内容に合わせたサイズにしてくれます。`width`や`height`を直接指定することもできます。

```swift
struct ScoreBoardView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            ScoreBoardView(name: "Taro", value: 100)
            ScoreBoardView(name: "とてもながーーーーーーいなまえ", value: 90)
        }.previewLayout(.sizeThatFits)
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130686/f40696ca-fdfc-eea5-719c-480c1ca6db7d.png">

- Color SchemeやDynamic Typeについては指定しなくてもXcodeがVariantsを一発で用意してくれます。確認しやすくしておいから対応してね、というAppleからのメッセージを感じますね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130686/ef3d4be2-6ff6-d912-1594-deae534b763e.png">


### Compose編
- SwiftUIと違って、デフォルトでは@Preview のサイズはコンテンツをラップできるように自動的に選択されますが、`showSystemUi`を付けることでステータスバー・アクションバーを表示することができます。もちろん`width`や`height`を直接指定することもできます。

![スクリーンショット 2022-12-13 22.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130686/d09c5525-9b0b-441d-54ab-5ee45a340c08.png)



- PreviewParameterProviderを渡すことで、サンプルデータをPreviewに渡すことができます。使いまわしもしやすく可読性も上がって便利ですね。SwiftUIにも欲しい。

![スクリーンショット 2022-12-13 22.10.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130686/2658bae7-fa7c-0233-c861-572a074467cb.png)


# 終わりに
実際の画面ではもう少し複雑なレイアウトを組み合わせることが多いですが、SwiftUI/Composeどちらかを知っていればかなり近い感覚でレイアウトを書くことができるので両OSやることになっても安心です。SwiftUI/Compose対応やっていき！


明日は@sansuke05さんの[Built-in VR から XR Plugin Management へ移行した話](https://qiita.com/sansuke05/items/cf8481a705d8fc19b99d)です！お楽しみに！