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