Sponsor Link
環境&対象
- macOS Monterey 12.1 Beta
- Xcode 13.1
- iOS 15
この記事は、以下の記事の続きです。
[SwiftUI][macOS] Table の使い方
前回記事のまとめ
前回の記事では、Table の使い方として以下を説明しました。
- 行を KeyPath 指定で表示する方法
- 行に表示データを データ要素から生成する方法
- Table 要素を選択できるようにする方法
ソートできる Table ビュー
集合要素に含まれる要素を、指定したソート順に表示させることができます。
ソート自体は別途実装する必要がありますが、関連する KeyPath を使用している行にソートのインディケータが表示されるようになります。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/10
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct Person: Identifiable {
public let id = UUID()
public var givenName: String
public var familyName: String
}
private var personList = [
Person(givenName: "Juan", familyName: "Chavez"),
Person(givenName: "Mei", familyName: "Chen"),
Person(givenName: "Tom", familyName: "Clark"),
Person(givenName: "Gita", familyName: "Kumar"),
]
struct ContentView: View {
@State private var persons = personList
@State private var sortOrder = [KeyPathComparator(\Person.givenName), KeyPathComparator(\Person.familyName)]
var body: some View {
VStack {
// (1)
Table(persons, sortOrder: $sortOrder) {
TableColumn("Given Name", value: \.givenName)
TableColumn("Family Name", value: \.familyName)
}
// (2)
.onChange(of: sortOrder) { newSortOrder in
persons.sort(using: newSortOrder)
}
}
}
- sortOrders を Table の引数として指定します
- 実際のソート操作は自分で実装する必要があります
ソートについては、NSTableView での実装と変わらない実装が可能になりそうです。
一部のデータ行要素についてのみ表示する Table ビュー
前回の記事では、集合要素(例えば Array)に含まれる要素全てについて表示していましたが、特定の要素についてのみ表示させることもできます。
例えば、前回から使用しているデータのうち、1番目、0番目、3番目の要素のみの表示にしてみます。(指定された通りの順番になります)
この例では、配列中の要素を指定していますが、配列に含まれている必要はありません。
# わかりにくいですが、personList の 1,0,3番目の要素が表示されています。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/10
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct Person: Identifiable {
public let id = UUID()
public var givenName: String
public var familyName: String
}
private var personList = [
Person(givenName: "Juan", familyName: "Chavez"),
Person(givenName: "Mei", familyName: "Chen"),
Person(givenName: "Tom", familyName: "Clark"),
Person(givenName: "Gita", familyName: "Kumar"),
]
struct ContentView: View {
@State private var persons = personList
var body: some View {
VStack {
Table {
TableColumn("Given Name", value:\.givenName)
TableColumn("Family Name", value:\.familyName)
} rows: {
// (1)
TableRow(persons[1])
TableRow(persons[0])
TableRow(persons[3])
}
}
}
}
- rows: 指定で、表示対象とするデータを指定します
表示したいデータをどの段階でフィルターするのかは、アプリ全体のアーキテクチャから決定する必要がありそうです。
現時点で提供されている機能で、外部から渡されたデータがすでにフィルターされていてもOKですし、自分でフィルターして表示することもできます。
一部のデータ行要素について動的に構成して表示する Table ビュー
rows 部分は、ResultBuilder になっているので、ループを使用して複数要素を指定するときは、ForEach を使用する必要があります。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/10
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct Person: Identifiable {
public let id = UUID()
public var givenName: String
public var familyName: String
}
private var personList = [
Person(givenName: "Juan", familyName: "Chavez"),
Person(givenName: "Mei", familyName: "Chen"),
Person(givenName: "Tom", familyName: "Clark"),
Person(givenName: "Gita", familyName: "Kumar"),
]
struct ContentView: View {
@State private var persons = personList
var body: some View {
VStack {
Table {
TableColumn("Given Name", value:\.givenName)
TableColumn("Family Name", value:\.familyName)
} rows: {
// (1)
ForEach(persons.reversed()) { person in
TableRow(person)
}
}
}
}
}
- rows にて、persons を逆順にしたものから TableRow を ForEach を使って生成する
データ要素について動的に列を構成して表示する Table ビュー は、できない?!
上記の rows と同様に、column についても動的に生成させられそうなのですが、column に対して ForEach は使えないようです・・・・
ForEach を column 内で使用するとコンパイルエラーとなります。
Xcode13.1 時点では、以下のエラーとなりました。
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
エラーの発生するコードは以下の通りです。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2021/06/10
// © 2021 SmallDeskSoftware
//
import SwiftUI
struct Person: Identifiable {
public let id = UUID()
public var givenName: String
public var familyName: String
public var memo: String = ""
}
private var personList = [
Person(givenName: "Juan", familyName: "Chavez"),
Person(givenName: "Mei", familyName: "Chen"),
Person(givenName: "Tom", familyName: "Clark"),
Person(givenName: "Gita", familyName: "Kumar"),
]
struct ContentView: View {
@State private var persons = personList
var body: some View {
VStack {
Table(persons) {
TableColumn("Given Name", value: \.givenName)
TableColumn("Family Name", value: \.familyName)
ForEach(1..3) { index in
TableColumn("many columns(\(index))") { person in
Text("Unknown column")
}
}
}
}
}
}
まとめ:SwiftUI Table の使い方(2)
- Table 定義時に sortOrder を指定すると、ソートのインディケータ表示含め ソート対応が可能となる(ソート自体の実装は別途必要)
- rows を使用することで、特定データの表示が可能となる
- TableColumn を動的に構成することは、難しそう(不具合かも??)
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link