我有一个数组buildingData,其中包含具有数字属性(当前存储为字符串)的Building结构。我正在制作一个视图,该视图提供单个建筑物的详细信息,并显示其每个属性相对于buildingData中其他建筑物的排名编号。
与其更明确地编写列表的每一行,我不希望使用通用视图结构rankRow,如下所示:
struct rankingRow : View {
var building : Building
var dataDescription : String
var dataValue: String
var body: some View {
HStack {
Text(dataDescription)
.fontWeight(.bold)
Text(dataValue)
Spacer()
RankingNumber( // Takes a rank (Int) and a size (Double) and makes a ranking graphic
rank: buildingData.sorted(by: { Double($0.overallSqm) ?? 0 > Double($1.overallSqm) ?? 0 }).firstIndex(of: building)! + 1,
size:28
)
}
}
}
但是,我不清楚如何简洁地将此结构传递给要排名的属性的名称(例如,上例中的totalSqm)。如何更改结构以使用以下方式生成列表:
List {
rankingRow(building:building, dataDescription:"Total Space (m2):", dataValue: building.overallSqm, rankedBy: .overallSqm)
rankingRow(building:building, dataDescription:”Public Space (m2):", dataValue: building.publicSqm, rankedBy: .publicSqm)
}
答案 0 :(得分:0)
现在,您的RankRow(s)取决于buildingData。如果您添加排名(以及其他 图形可能需要的数据)作为参数,可以简化视图。计算 排名最好在模型(或ViewModel)中进行(或扩展)。
要遍历建筑物的属性,可以在建筑物上实现下标。 使用枚举可避免需要检查无效键。您可以将扩展名添加到 方便提供数据描述的关键。使用ForEach遍历 在SwiftUI中构建属性。
import SwiftUI
struct Building {
let overallSqm: String
let publicSqm : String
}
// identifying buildings is necessary for calculating the rank, one of the options
// is to make Buidling conform to equatable
extension Building: Equatable {
static func ==(lhs: Building, rhs: Building) -> Bool {
return lhs.overallSqm == rhs.overallSqm && lhs.publicSqm == rhs.publicSqm
}
}
extension Building {
enum PropertyKey {
case overallSqm
case publicSqm
}
subscript(key: PropertyKey) -> String {
switch key {
case .overallSqm: return self.overallSqm
case .publicSqm: return self.publicSqm
}
}
}
extension Building {
func rank(in buildings: [Building], key: Building.PropertyKey) -> Int {
(buildings.sorted { (Double($0[key]) ?? 0) < (Double($1[key]) ?? 0) }.firstIndex { self == $0 } ?? 0) + 1
}
}
extension Building.PropertyKey {
var dataDescription: String {
switch self {
case .overallSqm: return "Total Space (m2):"
case .publicSqm: return "Public Space (m2):"
}
}
}
struct rankingRow: View {
let building : Building
let dataDescription: String
let dataValue : String
let rank : Int
var body: some View {
HStack {
Text(dataDescription)
.fontWeight(.bold)
Text(dataValue)
Spacer()
RankingNumber(rank: rank, size: 28)
}
}
}
struct RankingNumber: View {
let rank: Int
let size: CGFloat
var body: some View {
Text("Rank: \(rank)")
}
}
struct ContentView: View {
let buildings: [Building] = [
Building(overallSqm: "1000.0", publicSqm: "700.0" ),
Building(overallSqm: "1500.0", publicSqm: "600.0" ),
Building(overallSqm: "2000.0", publicSqm: "1200.0")
]
@State var building: Building = Building(overallSqm: "1000.0", publicSqm: "700.0")
let keys: [Building.PropertyKey] = [.overallSqm, .publicSqm]
func rank(for building: Building, key: Building.PropertyKey) -> Int {
(buildings.sorted { (Double($0[key]) ?? 0) < (Double($1[key]) ?? 0) }.firstIndex { building == $0 } ?? 0) + 1
}
var body: some View {
List {
ForEach(keys, id: \.self) { key in
rankingRow(
building : self.building,
dataDescription: key.dataDescription,
dataValue : self.building[key],
rank : self.rank(for: self.building, key: key))
}
}
}
}