【SwiftUI】ListをViewBuilderを使ってiOS15と16で分ける方法!
この記事からわかること
- Swift UIでList構造体で背景色をiOSのバージョンごとに分岐させる方法
- iOS16以降から使えるscrollContentBackgroundを設置するには?
- List × ViewBuilderの組み合わせ方
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
SwiftUIでListを使用時にscrollContentBackground
はiOS16以降からしか使えませんが15以前に対応したアプリを開発したいときにViewBuilder
を使ってiOS15と16でListを分けてみたので共有しておきます
ListのscrollContentBackgroundはiOS16からしか使えない
Listの背景色を変更したい時はiOS16以降であればscrollContentBackground
メソッドが使用できますが、以前ではイニシャライザからUITableView
のbackgroundColor
を変更する方法になります。
両者は記述方法がまるで違い、iOS15対応のアプリを開発時にscrollContentBackground
メソッドを記述するとavailable
による分岐が必要になります。
おすすめ記事:【Swift】#ifや#availableとは?コンパイラ制御ステートメントの使い方!
if #available(iOS 16.0, *) {
List {
Text("iOS16だよ")
}.scrollContentBackground(.hidden)
.listStyle(.grouped)
.background(Color.white)
} else {
List {
Text("iOS16より前だよ")
}.listStyle(.grouped)
}
しかしこのように記述するのは使いまわしたい時に使いまわしづらく、冗長的なので以下のように独自のViewであるAvailableListPlaneStack
を定義して使用できるように変更していきます。
AvailableListPlaneStack {
Text("iOS16だよ")
}
List × ViewBuilderでバージョン分けする
独自のスタックビューを実装するためにはViewBuilder
を使用します。@ViewBuilderとはクロージャから階層構造のビューを構築するためのResult Builderです。
詳細な実装方法は上記の記事を参考にしてください。ここではViewBuilderを使用して,AvailableListPlaneStack
を使用することでiOS16以降なら自動でscrollContentBackground
が付与されるようになりました。iOS16以前のUITableView
はイニシャライザからの指定をさせたいのでアプリのルートビューなどから呼び出しておいてください。
struct AvailableListPlaneStack<Content: View>: View {
var content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
if #available(iOS 16.0, *) {
List {
content
}.scrollContentBackground(.hidden)
.listStyle(.grouped)
.background(Color.white)
} else {
List {
content
}.listStyle(.grouped)
}
}
}
引数を渡して行から参照する
Listを使用するのであれば、配列などを引数に渡して中に参照したい場合が多いと思います。次は以下のように通常のListと同じようにcompletionHandler
を使用して参照できるようにしていきます。※独自のクラスBook
を定義しているものとします。
AvailableListBookStack(books: books) { book in
Text(book.title)
}
実装方法
実装方法は以下の通りになります。内部にプロパティを追加し、Content
のみだった箇所を@escaping (Book) -> Content
に変更しています。
struct AvailableListBookStack<Content: View>: View {
var content: (Book) -> Content
var books: [Book]
init(books: [Book], @ViewBuilder content: @escaping (Book) -> Content) {
self.books = books
self.content = content
}
var body: some View {
if #available(iOS 16.0, *) {
List(books) { book in
self.content(book)
}.listStyle(.grouped)
.scrollContentBackground(.hidden)
.background(Color.white)
} else {
List(books) { book in
content(book)
}.listStyle(.grouped)
}
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。