我正在尝试创建一个可重用的组件,用于将 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)
}
}
}
一个选择是引入通用类型必须符合的协议,并且
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() }