【问题标题】:SwiftUI allow all string enums in StructSwiftUI 允许 Struct 中的所有字符串枚举
【发布时间】:2020-10-09 19:54:45
【问题描述】:

这可能是一个愚蠢的问题,但我试图允许所有字符串枚举作为 Struct 中变量的类型。下面的代码是完全错误的,但我希望它能让我的问题更清楚。

我的想法是让所有枚举都遵循相同的协议,但我无法使用这种方法访问 .allCases。

我的目标是我可以将任何字符串枚举传递给 ListView,然后它将显示枚举的所有组件(这里:一;二;三)。

有人知道怎么做吗?它一定是一个非常基本的 Swift 东西,但我无法通过网络搜索找到它。非常感谢!

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        ListView(myEnum: Elements.self) //error here as well
    }
}

protocol StringRepresentable {
    var rawValue: String { get }
}

enum Elements: String, Equatable, CaseIterable, StringRepresentable {
    case one
    case two
    case three
}

struct ListView: View {
    let myEnum: StringRepresentable //doesn't work
    
    var body: some View {
        ForEach(myEnum.allCases, id: \.self) { elem in //can't access .allCases
            Text(elem.rawValue)
        }
    }
}

【问题讨论】:

    标签: ios swift enums swiftui


    【解决方案1】:

    您的原始代码中有几个错误。首先,您没有使用VStack(或ListLazyVStack),因此您的foreach 只会呈现一个元素。

    其次,您将类型而不是元素本身传递给列表视图。最后,您自己的StringRepresentable 协议是不必要的,您可以使用RawRepresentable 将其关联类型RawValue 限制为String

    即像这样:

    struct ContentView: View {
        var body: some View {
            VStack {
                ListView(values: Fruits.allCases)
                ListView(values: Animals.allCases)
            }
        }
    }
    
    enum Fruits: String, CaseIterable {
        case apple
        case orange
        case banana
    }
    
    enum Animals: String, CaseIterable {
        case cat
        case dog
        case elephant
    }
    
    struct ListView<T: RawRepresentable & Hashable>: View where T.RawValue == String {
        let values: [T]
    
        var body: some View {
            LazyVStack {
                ForEach(values, id: \.self) { elem in
                    Text(elem.rawValue)
                }
            }
        }
    }
    

    这样渲染

    【讨论】:

    • 您的解决方案很棒!传递 .allCases 确实更有意义!谢谢!
    【解决方案2】:

    这是一个变体,它通过将枚举的所有项发送到视图而不是枚举本身并使视图通用。

    struct ContentView: View {
        var body: some View {
            ListView(myEnum: Elements.allCases)
        }
    }
    
    protocol StringRepresentable {
        var rawValue: String { get }
    }
    
    enum Elements: String, Equatable, CaseIterable, StringRepresentable {
        case one
        case two
        case three
    }
    
    struct ListView<T: CaseIterable & StringRepresentable>: View {
        let myEnum: [T]
        @State private var selectedValue: String = ""
    
        var body: some View {
            ForEach(0..<myEnum.count) { index in
                Text(myEnum[index].rawValue)
                    .onTapGesture {
                        selectedValue = myEnum[index].rawValue
                    }
            }
        }
    }
    

    【讨论】:

    • 但我不想那样做!我希望 Struct 可以与不同的枚举一起使用,这样我就不必为不同的枚举类型多次编写 Struct。
    • 谢谢!但我想你没明白我的意思。我希望 ListView 的 myEnum 可以是任何 Enum 类型,只要它符合 RawRepresentable 即可。 ListView 然后应该列出该枚举的实例可能具有的所有原始值(这里:一、二和三应该出现在列表中。)。
    • 你是对的。忘记改了,非常抱歉!我删除了那部分。
    • 非常感谢!工作很棒!真的要再看看 Swift Generics。我现在想同时接受这两个答案...
    猜你喜欢
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    相关资源
    最近更新 更多