如何创建可以显示多个对象的视图?

How to create a view that can display multiple objects?

提问人:phroureo 提问时间:11/15/2023 最后编辑:HangarRashphroureo 更新时间:11/16/2023 访问量:60

问:

我有一个视图,如下所示:

struct CardView: View {
    let item: Items

    var body: some View {
        VStack(alignment: .center) {
            Text("\(item.name)")
                .font(.headline)
                .accessibilityAddTraits(.isHeader)
            Spacer()
            HStack {
                Label("\(item.description)", systemImage: "questionmark.square.dashed")
            }
            .font(.caption)
        }
        .padding()
    }
}

struct CardView_Previews: PreviewProvider {
    static var item = Items.abilityScores[0]
    static var previews: some View {
        CardView(item: item)
            .previewLayout(.fixed(width: 400, height: 60))
    }
}

(Items.abilityScores是我在类文件中生成的列表。如果需要,我可以告诉你。Items

我想将此视图重用于各种类型的几个不同对象。

有几种可能的方式,我可以看到这种情况的进展:

  1. 我为 创建一个基类,然后将其传递给具有更多属性/vars/其他的一堆其他类。我怀疑我能做到这一点。Item
  2. 我单独创建每个类,即使它们在实现/用法上都非常相似,并为每个类创建单独的视图。
  3. 别的?也许创建参数并给它们所有相同的字段名称,然后做一些喜欢的事情,在尝试显示它们之前检查值是否存在或其他东西?AnyObject

#1 甚至可能吗?还是我屈服于#2 并为不同的对象一遍又一遍地创建相同的视图?

迅捷 SwiftUI

评论

0赞 lorem ipsum 11/15/2023
查找协议和/或继承和泛型,只要这些对象具有可以共享的共同点。理想情况下,比 AnyObject 更具体的东西,因为 AnyObject 没有任何实际的显示值
0赞 phroureo 11/16/2023
@loremipsum我熟悉协议,但问题又回到了“我是否可以让视图需要一个协议作为输入,以允许我传递一个继承它的类?
0赞 Larme 11/16/2023
可能的解决方案:ViewModel。一个 ViewModel 结构,可以由您的每个类型初始化,并且您放置它们需要显示的每个值。
0赞 lorem ipsum 11/16/2023
是的,AnyObject 需要一个类。可以使用协议或基类
0赞 phroureo 11/16/2023
@loremipsum 谢谢,这很有帮助。如果我的协议有一个 name 属性和一个 description 属性,但实现它的结构之一也有一个“ShortName”属性,如果它是一个存在的字段,是否可以将其也放在视图中?我的直觉说“仍然没有”,因为编译器会吓坏了,但也许我错了。

答:

0赞 trojanfoe 11/16/2023 #1

这个怎么样?

protocol ItemProtocol {
    func name() -> String
    func description() -> String
    func optionalThing() -> String?
}

struct Item1: ItemProtocol {
    var n: String
    var d: String
    var t: String
    func name() -> String {
        n
    }
    func description() -> String {
        d
    }
    func optionalThing() -> String? {
        t
    }
}

struct Item2: ItemProtocol {
    var n: String
    var d: String
    func name() -> String {
        n
    }
    func description() -> String {
        d
    }
    func optionalThing() -> String? {
        nil
    }
}


struct CardView: View {
    let item: ItemProtocol

    var body: some View {
        VStack(alignment: .center) {
            Text("\(item.name())")
                .font(.headline)
                .accessibilityAddTraits(.isHeader)
            Spacer()
            HStack {
                Label("\(item.description())", systemImage: "questionmark.square.dashed")
                if let optionalThing = item.optionalThing() {
                    Label("\(optionalThing)", systemImage: "questionmark.square.dashed")
                }
            }
            .font(.caption)
        }
        .padding()
    }
}

跟:

let viewController = NSHostingController(rootView: CardView(item: Item1(n: "Name1", d: "Description1", t: "Optional Thing")))

enter image description here

跟:

let viewController = NSHostingController(rootView: CardView(item: Item2(n: "Name2", d: "Description2")))

enter image description here

评论

0赞 phroureo 11/16/2023
谢谢 -- 我有类似的东西。当具有协议不需要的属性时,会出现我的问题 - 例如,我有一个具有“短”属性的结构。我现在正在努力解决如何在视图中实现该功能的问题,即如果结构具有属性,则显示它,如果这有意义?Item1Item
0赞 trojanfoe 11/16/2023
你可以向协议添加一个返回可选事物的方法,如果它不是 nil,则显示它,否则显示默认值或不显示任何内容。
0赞 trojanfoe 11/16/2023
@phroureo编辑。
0赞 phroureo 11/16/2023
啊,所以我还需要把协议放在协议中,然后传递给每个孩子?这就是我所假设的,但试图避免/看看是否有更好的方法。感谢您的帮助!OptionalThingnil
0赞 trojanfoe 11/16/2023
@phroureo 很可能有更好的方法;我的 Swift 生锈了 :~|