如何更改排序比较器或显示Int?macOS上带有SwiftUI的表上的值



我有一个下表,当所有列值都是字符串时,它大多有效:

struct Person : Identifiable {
let id: String // assume names are unique for this example
let name: String
let rank: String
}
@State var people = []
@State var sort = [KeyPathComparitor(Person.rank)]
@State var selection: Person.ID? = nil
private var rankingsCancellable: AnyCancellable? = nil
init (event: Event) {
rankingsCancellable = event.rankingsSubject 
.receive(on: DispatchQueue.main)
.sink { rankings in 
var newRankings: [Person] = []
for ranking in rankings {
newRankings.append(Person(id: ranking.name, name: ranking.name, ranking: ranking.rank
}
newRankings.sort(by: sort)
people = newRankings
}
}
var body : some View {
Table(people, selection: $selection, sortOrder: $sort) {
TableColumn("Name", value: Person.name)
TableColumn("Rank", value: Person.rank)
}
.onChange(of: sortOrder) {
people.sort(using: $0)
}
}

这一点很好,只有一个例外,当秩未知进入接收器时,它作为空字符串发送,并且空字符串在具有有效秩的字符串之前排序。理想情况下,我希望那些没有排名的人在收到排名之前进行排序。

我尝试了几件事,将Person.rank更改为Int,但编译器在以下情况下给出了典型的"太复杂"错误:

TableColumn("Rank", value: Person.rank) { Text(($0.rank)) } // rank is an int here

或者,我试图在创建KeyPathComparator(Person.rank)时创建一个自定义排序比较器,但相关文档有限,无法找到可行的解决方案。

有什么想法可以让表简单地显示Ints(我想在这种情况下必须是可选的(,或者添加一个字符串比较器,将空字符串移动到填充字符串下面?

TIA-

这是我能找到的最好的答案,尽管我承认这看起来有点像拼凑。基本上添加Int属性进行排序,并将排序设置为此Person属性的初始排序

struct Person : Identifiable {
let id: String // assume names are unique for this example
let name: String
let rank: String
//Add rankForSort as an int which is a non displayed column
let rankForSort: Int
}
@State var people = []
//Change to initial sort to non-displayed rank field
@State var sort = [KeyPathComparitor(Person.rankForSort)]

@State var selection: Person.ID? = nil
private var rankingsCancellable: AnyCancellable? = nil
init (event: Event) {
rankingsCancellable = event.rankingsSubject 
.receive(on: DispatchQueue.main)
.sink { rankings in 
var newRankings: [Person] = []
for ranking in rankings {
// Ranking now coming through in the subject as Int?
let rankString = ranking.rank != nil ? "(ranking.rank!)" : ""
newRankings.append(Person(id: ranking.name, name: ranking.name, ranking: rankString, rankForSort: ranking.rank ?? Int.max)
}
newRankings.sort(by: sort)
people = newRankings
}
}
var body : some View {
Table(people, selection: $selection, sortOrder: $sort) {
TableColumn("Name", value: Person.name)
TableColumn("Rank", value: Person.rank)
}
.onChange(of: sortOrder) {
people.sort(using: $0)
}
}

这里有一种进行初始排序的方法,并使用didSet,这有一个额外的好处,即不使用onChange,这会导致在调用时调用两次body。

struct ProductsData {
var sortedProducts: [Product]
var sortOrder = [KeyPathComparator(Product.name)] {
didSet {
sortedProducts.sort(using: sortOrder)
}
}

init() {
sortedProducts = myProducts.sorted(using: sortOrder)
}
}
struct ContentView: View {
@State private var data = ProductsData()

var body: some View {
ProductsTable(data: $data)
}
}
struct ProductsTable: View {
@Environment(.horizontalSizeClass) private var horizontalSizeClass
@Binding var data: ProductsData

var body: some View {
Table(data.sortedProducts, sortOrder: $data.sortOrder) {

请参阅完整样本中不同问题的答案。

最新更新