【SwiftUI】ListをViewBuilderを使ってiOS15と16で分ける方法!

この記事からわかること

  • Swift UIList構造体背景色iOSバージョンごとに分岐させる方法
  • iOS16以降から使えるscrollContentBackgroundを設置するには?
  • List × ViewBuilder組み合わせ方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

SwiftUIでListを使用時にscrollContentBackgroundiOS16以降からしか使えませんが15以前に対応したアプリを開発したいときにViewBuilderを使ってiOS15と16でListを分けてみたので共有しておきます

ListのscrollContentBackgroundはiOS16からしか使えない

Listの背景色を変更したい時はiOS16以降であればscrollContentBackgroundメソッドが使用できますが、以前ではイニシャライザからUITableViewbackgroundColorを変更する方法になります。

両者は記述方法がまるで違い、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)
        }
    }
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index