制作符合 SwiftUI 协议的结构列表
Make a list of Structs conform to a protocol SwiftUI
我有一个自定义协议说
protocol CustomProtocol {}
我有一个自定义结构 say
struct CustomStruct: View, CustomProtocol
如何使 (CustomStruct, CustomStruct) 符合 CustomProtocol
我有一个自定义 ViewBuilder,它有一个初始化函数,
init<views>(@ViewBuilder content: @escaping () -> TupleView<Views>)
现在我只想接受符合 CustomProtocol
的视图
示例:
struct CustomStruct: View {
var views: [AnyView]
init<Views: CustomProtocol>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
self.views = content().getViews
}
我为 getViews 变量添加了元组视图的扩展:
extension TupleView {
var getViews: [AnyView] {
makeArray(from: value)
}
private struct GenericView {
let body: Any
var anyView: AnyView? {
AnyView(_fromValue: body)
}
}
private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
func convert(child: Mirror.Child) -> AnyView? {
withUnsafeBytes(of: child.value) { ptr -> AnyView? in
let binded = ptr.bindMemory(to: GenericView.self)
return binded.first?.anyView
}
}
let tupleMirror = Mirror(reflecting: tuple)
return tupleMirror.children.compactMap(convert)
}
}
我能想到的唯一方法就是重新发明你自己的ViewBuilder
:
@resultBuilder
struct MyCustomViewBuilder {
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol {
ViewBuilder.buildBlock(c0, c1)
}
static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol, C2: View & CustomProtocol {
ViewBuilder.buildBlock(c0, c1, c2)
}
// and so on...
}
ViewBuilder
有最多 10 个视图的 buildBlock
重载(这就是为什么你不能在 ViewBuilder
中放置超过 10 个视图的原因),所以你可以写如果你也想的话,可以重载 10 次。不幸的是,无法使用可变参数,因为 View
具有关联类型:(
然后你可以这样做例如:
struct CustomStack<Views>: View {
var body: some View {
content
}
let views: [AnyView]
let content: TupleView<Views>
// note the change from @ViewBuilder to @CustomViewBuilder
init(@MyCustomViewBuilder content: @escaping () -> TupleView<Views>) {
let view = content()
self.views = view.getViews
self.content = view
}
}
现在如果你这样做:
CustomStack {
Text("Hello")
Text("World")
}
编译器会抱怨Text
不符合CustomProtocol
。
我有一个自定义协议说
protocol CustomProtocol {}
我有一个自定义结构 say
struct CustomStruct: View, CustomProtocol
如何使 (CustomStruct, CustomStruct) 符合 CustomProtocol
我有一个自定义 ViewBuilder,它有一个初始化函数,
init<views>(@ViewBuilder content: @escaping () -> TupleView<Views>)
现在我只想接受符合 CustomProtocol
的视图
示例:
struct CustomStruct: View {
var views: [AnyView]
init<Views: CustomProtocol>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
self.views = content().getViews
}
我为 getViews 变量添加了元组视图的扩展:
extension TupleView {
var getViews: [AnyView] {
makeArray(from: value)
}
private struct GenericView {
let body: Any
var anyView: AnyView? {
AnyView(_fromValue: body)
}
}
private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
func convert(child: Mirror.Child) -> AnyView? {
withUnsafeBytes(of: child.value) { ptr -> AnyView? in
let binded = ptr.bindMemory(to: GenericView.self)
return binded.first?.anyView
}
}
let tupleMirror = Mirror(reflecting: tuple)
return tupleMirror.children.compactMap(convert)
}
}
我能想到的唯一方法就是重新发明你自己的ViewBuilder
:
@resultBuilder
struct MyCustomViewBuilder {
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol {
ViewBuilder.buildBlock(c0, c1)
}
static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View & CustomProtocol, C1 : View & CustomProtocol, C2: View & CustomProtocol {
ViewBuilder.buildBlock(c0, c1, c2)
}
// and so on...
}
ViewBuilder
有最多 10 个视图的 buildBlock
重载(这就是为什么你不能在 ViewBuilder
中放置超过 10 个视图的原因),所以你可以写如果你也想的话,可以重载 10 次。不幸的是,无法使用可变参数,因为 View
具有关联类型:(
然后你可以这样做例如:
struct CustomStack<Views>: View {
var body: some View {
content
}
let views: [AnyView]
let content: TupleView<Views>
// note the change from @ViewBuilder to @CustomViewBuilder
init(@MyCustomViewBuilder content: @escaping () -> TupleView<Views>) {
let view = content()
self.views = view.getViews
self.content = view
}
}
现在如果你这样做:
CustomStack {
Text("Hello")
Text("World")
}
编译器会抱怨Text
不符合CustomProtocol
。