如何接受可在 SwiftUI 文本视图中使用的任何变量类型

问题描述 投票:0回答:1

我正在尝试创建一个可重用的组件,用于将 Swift 集合 OrderedSet 呈现到 SwiftUI 列表中,并具有删除、移动和添加处理程序。

我希望能够传入可直接用作插值字符串的任何类型的 OrderedSet,例如

Text("hello \(myGenericTypeLikeAStringIntOrFloat) world")

我一直在尝试找到一个可以帮助我定义这些通用类型的协议,并认为

ExpressibleByStringInterpolation
可能会有所帮助,但我认为这仅用于创建您自己的可在 SwiftUI 文本视图中使用的类型。

我在

Text("\(item)")
行遇到的错误是
No exact matches in call to instance method 'appendInterpolation'

有没有办法调整我的 OrderedSet 以仅接受可在文本视图中使用的项目?

这是一个精简的示例,希望能更好地解释它。


import SwiftUI
import OrderedCollections


struct ReusableListView<Element: Hashable>: View {
    
    @Binding var set: OrderedSet<Element>
    
    @State private var multiSelection: Set<String> = []
    
    init(_ set: Binding<OrderedSet<Element>>) {
        self._set = set
    }
    
    var body: some View {
        Section {
            List(selection: $multiSelection) {
                ForEach(set, id: \.self) { item in
                    Text("\(item)")
                }
                .onDelete { indexSet in
                    set.elements.remove(atOffsets: indexSet)
                }
            }
        }
    }
}


@main
struct MyApp: App {
    
    @State private var setWithStrings: OrderedSet<String> = ["hello", "world"]
    @State private var setWithInts: OrderedSet<Int> = [1, 2, 3]
    
    var body: some Scene {
        
        WindowGroup {
            ReusableListView($setWithStrings)
            ReusableListView($setWithInts)
        }
    }
}
ios swift macos swiftui string-interpolation
1个回答
0
投票

一个选择是引入通用类型必须符合的协议,并且

Text
可以利用该协议

protocol TextSupport {
    var text: String { get }
}

然后我们将视图的声明更改为

struct ReusableListView<Element: Hashable & TextSupport>: View

并在视图中使用该属性

ForEach(set, id: \.self) { item in
    Text("\(item.text)")
}

那么您需要遵守您使用的任何类型的协议

extension String: TextSupport {
    var text: String { self }
}
extension Int: TextSupport {
    var text: String { self.formatted() }
}

另一种选择是向视图添加一个闭包属性,以便视图的每个实现都通过自己的方式将

Element
类型转换为
String

var convert: (Element) -> String

该属性在 init 中设置

init(_ set: Binding<OrderedSet<Element>>, convert: @escaping (Element) -> String) {
    self._set = set
    self.convert = convert
}

并在

ForEach

中使用它
ForEach(set, id: \.self) { item in
    Text("\(convert(item))")
}

然后用闭包调用视图

ReusableListView($setWithStrings) { $0 }
ReusableListView($setWithInts) { $0.formatted() }
© www.soinside.com 2019 - 2024. All rights reserved.