【SwiftUI】ListのModifierについて

# はじめに

ListのUIを調整できるModifierについて調べてみました。

https://developer.apple.com/documentation/swiftui/lists

# 環境
Xcode 14.0

# 内容

以前、Listの基本的なこと、主にスタイルなどについて👇の記事でまとめたので、
今回は前回記事で参考にした公式ドキュメントのコードをベースにListのmodifierについて調べていきます。

https://qiita.com/yoshitaka/items/ee8f9217fab70e0b484f

```swift
import SwiftUI

struct ListView: View {
    struct Sea: Hashable, Identifiable {
        let name: String
        let id = UUID()
    }
    
    struct OceanRegion: Identifiable {
        let name: String
        let seas: [Sea]
        let id = UUID()
    }
    
    private let oceanRegions: [OceanRegion] = [
        OceanRegion(name: "Pacific",
                    seas: [Sea(name: "Australasian Mediterranean"),
                           Sea(name: "Philippine"),
                           Sea(name: "Coral"),
                           Sea(name: "South China")]),
        OceanRegion(name: "Atlantic",
                    seas: [Sea(name: "American Mediterranean"),
                           Sea(name: "Sargasso"),
                           Sea(name: "Caribbean")]),
        OceanRegion(name: "Indian",
                    seas: [Sea(name: "Bay of Bengal")]),
        OceanRegion(name: "Southern",
                    seas: [Sea(name: "Weddell")]),
        OceanRegion(name: "Arctic",
                    seas: [Sea(name: "Greenland")])
    ]
    
    var body: some View {
        List {
            ForEach(oceanRegions) { region in
                Section {
                    ForEach(region.seas) { sea in
                        Text(sea.name)
                    }
                } header: {
                    Text(region.name)
                }
            }
        }
        .listStyle(.plain)
    }
}
```
<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/00f9e305-7a31-80ac-e24e-b373ece538bb.png">

## リストの背景色
#### [scrollContentBackground(_:)](https://developer.apple.com/documentation/swiftui/text/scrollcontentbackground(_:))
スクロール可能なViewの背景の可視性を指定
`Visibility`：`.automatic`, `.visible`, `.hidden`

```diff_swift
    List {
        ForEach(oceanRegions) { region in
            Section {
                ForEach(region.seas) { sea in
                    Text(sea.name)
                }
            } header: {
                Text(region.name)
            }
        }
    }
+   .scrollContentBackground(.hidden)
+   .background(Color.green)
    .listStyle(.plain)
```

`.hidden`を設定することで、リストの背景色を`.background(Color.green)`で変えることができる

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/b49121c7-666a-4115-7965-e7b68930d415.png">

## セルの背景色
#### [listRowBackground(_:)](https://developer.apple.com/documentation/swiftui/list/listrowbackground(_:))
リスト行アイテムの後ろにカスタム背景Viewを配置

```diff_swift
    List {
        ForEach(oceanRegions) { region in
            Section {
                ForEach(region.seas) { sea in
                    Text(sea.name)
                }
            } header: {
                Text(region.name)
            }
        }
+       .listRowBackground(Color.yellow)
    }
    .listStyle(.plain)
```

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/a6cb2b2a-4155-2e6c-2c6d-a3321e1ea0f6.png"><img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/e6f8e3e3-0701-ec23-4dfc-0377cc1dafa0.png">

## セルの位置調整
#### [listRowInsets(_:)](https://developer.apple.com/documentation/swiftui/view/listrowinsets(_:))
リストセルとして使用する場合、指定されたエッジインセットを使用

```diff_swift
    List {
        ForEach(oceanRegions) { region in
            Section {
                ForEach(region.seas) { sea in
                    Text(sea.name)
                }
            } header: {
                Text(region.name)
            }
        }
+       .listRowInsets(EdgeInsets())
        .background(Color.orange)
        .listRowBackground(Color.yellow)
    }
    .scrollContentBackground(.hidden)
    .background(Color.green)
    .listStyle(.plain)
```

`.listRowInsets`で値を設定することで、セルの位置調整ができる

① デフォルト
②`.listRowInsets(EdgeInsets())`
③`.listRowInsets(EdgeInsets(top: 10.0, leading: 50.0,bottom: 30.0, trailing: 10.0))`

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/d880e35c-abc9-84a8-9fb5-c2175c4ec043.png">
<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/c23a8120-d7cf-9b51-6f33-dbd1d438f131.png">
<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/d17f6fe9-c97a-891c-a936-300a9e8c52d2.png">




## セパレーター
#### [listRowSeparatorTint(_:edges:)](https://developer.apple.com/documentation/swiftui/view/listrowseparatortint(_:edges:))
リストの行に関連する色を設定

#### [listSectionSeparatorTint(_:edges:)](https://developer.apple.com/documentation/swiftui/view/listsectionseparatortint(_:edges:))
セクションに関連する色を設定

#### [listRowSeparator(_:edges:)](https://developer.apple.com/documentation/swiftui/view/listrowseparator(_:edges:))
リストの行に関連付けられたセパレータの表示モードを設定

#### [listSectionSeparator(_:edges:)](https://developer.apple.com/documentation/swiftui/view/listsectionseparator(_:edges:))
リストセクションに関連付けられたセパレータを表示モードを設定

```swift
    ForEach(oceanRegions) { region in
        Section {
            ForEach(region.seas) { sea in
                Text(sea.name)
            }
        } header: {
            Text(region.name)
        }
    }
    .listRowSeparatorTint(Color.blue)
    .listSectionSeparatorTint(Color.red)
    .listRowSeparator(.hidden, edges: .all)
    .listSectionSeparator(.visible, edges: .all)
```

`VerticalEdge.Set`： `.all`, `.buttom`, `.top`
`Visibility`: `.automatic,` `.visible,` `.hidden`

Listのコンテンツに上記の全てを適当に追加してみました。

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/c27aa249-d06a-ac26-deae-7d54a5d211af.png">

セクションに青色のセパレーターが表示されるのみの状態を期待しました(`.listSectionSeparatorTint(Color.red)`は不要ですが)
が、残念ながら期待通りのUIにはなりませんでした。。。
（これはバグなのか?）


```diff_swift
    List {
        ForEach(oceanRegions) { region in
            Section {
                ForEach(region.seas) { sea in
                    Text(sea.name)
                }
            } header: {
+               VStack {
                    Text(region.name)
+                       .padding(.leading, 10.0)
+                       .padding(.bottom, 5.0)
+                       .frame(maxWidth: .infinity, alignment: .leading)
+               }
+               .listRowInsets(EdgeInsets())
+               .overlay(
+                   Rectangle()
+                       .frame(height: 1.0)
+                       .foregroundColor(.blue),
+                   alignment: .bottom
+               )
            }
        }
+       .listRowSeparator(.hidden)
+       .listSectionSeparator(.hidden)
    }
    .listStyle(.plain)
```


`.listRowSeparator(.hidden)`,`.listSectionSeparator(.hidden)`として
`.overlay`を使い、その他少し調整を入れることで、それっぽい見た目になりました
（もっと良い実装ありそうな気もしますが。。。）

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/f95a8235-828b-178c-a712-e76c6c36577d.png">

## その他気になったもの
#### [scrollDisabled(_:)](https://developer.apple.com/documentation/swiftui/text/scrolldisabled(_:))
スクロール可能なViewでのスクロールを無効または有効に設定

#### [scrollDismissesKeyboard(_:)](https://developer.apple.com/documentation/swiftui/text/scrolldismisseskeyboard(_:))
スクロール時のキーボードの動作を設定
`ScrollDismissesKeyboardMode`：`.automatic`, `.immediately`, `.interactively`, `.never`

#### [scrollIndicators(_:axes:)](https://developer.apple.com/documentation/swiftui/text/scrollindicators(_:axes:))
スクロールインジケータの可視性を設定
`ScrollIndicatorVisibility`：`.automatic`, `.hidden`, `.never`, `.visible`

# おわりに
リストに使えるModifierは他にもたくさんあるので、引き続き整理していきたいと思います。

# 参考

https://zenn.dev/tsuzuki817/articles/fb5f6261945af6

https://capibara1969.com/3874/

https://webtopi.biz/archives/31653757382196

https://nilcoalescing.com/blog/AdjustListRowSeparatorInsets/

https://sarunw.com/posts/swiftui-list-row-separator-insets/