SwiftUI で階層構造を持った List を表示するサンプルです。
【SwiftUI】ネスト(階層化)した List を表示する
DataModel
先ずはデータ型を定義します。
struct DataModel: Identifiable {
let id = UUID()
let name: String
var subItems: [DataModel]?
}
DataModel はサブデータとして subItems という名称の DataModel の配列を保持しています。
ViewModel
今回は DataModel を保持する ViewModel を定義しました。データの初期化を行っています。
View で保持しても良いので ViewModel は必須ではありません。
class ViewModel: ObservableObject {
@Published var dataModel = [DataModel]()
init() {
var subItems = [DataModel]()
for i in 0..<5 {
subItems.append(DataModel(name: "SubItem \(i)"))
}
dataModel = [
DataModel(name: "Item 1", subItems: subItems),
DataModel(name: "Item 2", subItems: subItems),
DataModel(name: "Item 3", subItems: subItems),
DataModel(name: "Item 4", subItems: subItems),
DataModel(name: "Item 5", subItems: subItems),
DataModel(name: "Item 6", subItems: subItems),
DataModel(name: "Item 7", subItems: subItems),
]
}
}
ContentView
ポイントとなる List の表示方法です。
List の第2引数の children: に DataModel で定義した subItems を id として渡します。
渡すときは \.subItem というように「\(バックスラッシュ).(ドット)」を頭に付けます。
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
List(viewModel.dataModel, children: \.subItems) { item in
Text(item.name)
}
}
}
このようにするだけで、冒頭の動画のように開閉可能なネストしたテーブルを表示することが出来ます。UIKit に比べるととてもシンプルに実装できるようになった印象です。
以上
上記のコードはViewController.swiftのclass ViewController: UIViewController, UITableViewDelegate,UITableViewDataSourceのスコープ内に書いてみたのですが実装できないです。CocoaTouchClassのファイルとかに書いてインポートとかするのでしょうか?ファイルの全体が見たいです。
char char さん
お返事が遅くなりすみません。
>上記のコードはViewController.swiftのclass ViewController: UIViewController, UITableViewDelegate,UITableViewDataSourceのスコープ内に書いてみたのですが実装できないです。
コメントの内容から察するに、SwiftUIではなくて旧来のUIKitでの利用を想定しておりますでしょうか。
本記事の内容はSwiftUIを主眼に置いた記事ですので、UIViewController等を使ったUIKitプロジェクトのコードには適用できません。
両者はともにSwift言語でiOSアプリを作成するものですが、画面の作り方が全く異なります。
Xcodeのプロジェクトを作成するときにSwiftUIを選択してプロジェクトを生成してみて下さい。
ちなみにSwiftUIで作成したViewをUIKitで使うということもできますが、下記の記事のような利用を想定してのコメントでしたらごめんなさい(筆者は試していません)。
https://www.yururiwork.net/archives/451
返事ありがとうございます。
SwiftUIとUIKitの違いもよくわかってなかったレベルですのでトンチンカンですみません。
このコードをContentView.swiftに書くとContentView_Previewsのところで,
Missing argument for parameter ‘viewModel’ in callというエラー出ます。
いろいろなコードを書いてて思ったのが、最初に表示するためのviewModelの引数が必要だ、というエラーだと思ってます。
どのようにすればいいのでしょうか?
static var previews: some View {
ContentView()//ここでエラーが出ます。
}
ここのエラーのFixを押すとContentView(viewModel: ViewModel)になります。
ここに渡すためのViewModelを生成しないといけないと思ってますがどうなんでしょうか?
>ここに渡すためのViewModelを生成しないといけないと思ってますがどうなんでしょうか?
ContentView(viewModel: .init())
でいけるかと思います。
ContentView(viewModel: ViewModel.init())
でも同じです。
init() とはイニシャライザー(別名コンストラクタ)と言ってオブジェクト(classとかstruct)を生成する時に呼ぶものです(少し調べてみてください)。
ちなみに
static var previews: some View {}
はXcode上で簡易的にView確認するためのコードですので、
不要な場合は丸ごと削除してOKです。
ビルドは通りますし実行もできます。