iOS14環境でListの罫線が欠ける問題の解消方法

## はじめに

iOS14環境でListを使用するとコンテンツの下に置いた罫線のうち、何箇所かがレンダリング時に消えてしまう問題が発生。チームの開発メンバーに解決方法をお聞きしたので、備忘録として記載。

## 結論

少々トリッキーだが、Listのアイテムの**上に置くことで解決**する

サンプルコードは以下の通り

```
import SwiftUI

struct TextData: Identifiable {
    var id: String {
        text
    }
    // textは一意であるとする
    var text: String
}

struct ContentView: View {
    // サンプルデータ
    let textDataList: [TextData] = [.init(text: "test1"), .init(text: "text2"), .init(text: "text3")]

    var body: some View {
        List {
            ForEach(textDataList, content: listContent)
                .listRowSeparatorHidden()
                .listRowInsets(.init())
                .listRowBackground(Color(.white))
        }
        .listStyle(.plain)
    }

    private func listContent(textData: TextData) -> some View {
        VStack(spacing: 10) {
            // 上に置くことで解決する
            divider

            HStack(spacing: 0) {
                Text(textData.text)

                Spacer()

                Image(systemName: "chevron.right")
            }

            // 最後のアイテムの下の罫線の表示ロジック
            if textData.id == textDataList.last?.id {
                divider
            }
        }
    }

    private var divider: some View {
        Divider()
            .background(Color(.gray))
            .frame(maxWidth: .infinity)
    }
}

extension View {
    // iOS14番台でListのデフォルトの罫線を非表示にするextension
    // .listRowSeparator(.hidden)が使えないため
    func listRowSeparatorHidden() -> some View {
        frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
            .listRowInsets(.init(top: -1, leading: -1, bottom: -1, trailing: -1))
            .background(Color(UIColor.systemBackground))
    }
}
```

## これで解決と思いきや...

**今度はiOS15環境で罫線が欠ける問題が発生..**

そのため、バージョンで分岐をする。バージョン分岐を加えたコードがこちら。

```
import SwiftUI

struct TextData: Identifiable {
    var id: String {
        text
    }
    // textは一意であるとする
    var text: String
}

struct ContentView: View {
    // サンプルデータ
    let textDataList: [TextData] = [.init(text: "test1"), .init(text: "text2"), .init(text: "text3")]

    var body: some View {
        List {
            if #available(iOS 15.0, *) {
                ForEach(textDataList, content: listContentIOS15)
                    .listRowSeparator(.hidden)
                    .listRowInsets(.init())
                    .listRowBackground(Color(.white))

            } else {
                ForEach(textDataList, content: listContent)
                    .listRowSeparatorHidden()
                    .listRowInsets(.init())
                    .listRowBackground(Color(.white))
            }
        }
        .listStyle(.plain)
    }

    private func listContentIOS15(textData: TextData) -> some View {
        VStack(spacing: 10) {
            HStack(spacing: 0) {
                Text(textData.text)

                Spacer()

                Image(systemName: "chevron.right")
            }

            // iOS15.0では通常通り下に罫線を置く
            divider
        }
    }

    private func listContent(textData: TextData) -> some View {
        VStack(spacing: 10) {
            // 上に置くことで解決する
            divider

            HStack(spacing: 0) {
                Text(textData.text)

                Spacer()

                Image(systemName: "chevron.right")
            }

            // 最後のアイテムの下の罫線の表示ロジック
            if textData.id == textDataList.last?.id {
                divider
            }
        }
    }

    private var divider: some View {
        Divider()
            .background(Color(.gray))
            .frame(maxWidth: .infinity)
    }
}

extension View {
    // iOS14番台でListのデフォルトの罫線を非表示にするextension
    // .listRowSeparator(.hidden)が使えないため
    func listRowSeparatorHidden() -> some View {
        frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
            .listRowInsets(.init(top: -1, leading: -1, bottom: -1, trailing: -1))
            .background(Color(UIColor.systemBackground))
    }
}
```

## 結論

iOS14はSwiftUIが導入されて間もない時にリリースされたバージョンなので、他にも色々バグが見つかっており、その度に頭を悩ませています。他にもあれば、その都度共有させていただきます。