首先,此代码的错误之处在于它会产生编译错误:
"Cannot convert the return expression of type '_ConditionalContent<MyView, MyView>' to the return type 'MyView'."
每个分支都隐式返回 MyView
类型。 其次,有没有一种方法可以绕过使用AnyView
并利用泛型编写代码?
import SwiftUI
private struct ControllerView: View {
let rootView: () -> MyView
@Binding var isGreen: Bool
init(isGreen: Binding<Bool>,@ViewBuilder rootView: @escaping () -> MyView) {
self.rootView = rootView
self._isGreen = isGreen
}
var body: some View {
ZStack {
rootView()
Button {
isGreen.toggle()
} label: {
Text("Change")
}
}
}
}
private struct GreenView: View {
var body: some View {Color.green.ignoresSafeArea()}
}
private struct OrangeView: View {
var body: some View {Color.orange.ignoresSafeArea()}
}
private struct MyView: UIViewControllerRepresentable {
let rootView: AnyView
init(rootView: AnyView) {
self.rootView = rootView
print("init MyView")
}
func makeUIViewController(context: Context) -> UIViewController {
print("makeUI")
/// create my custom VC
return UIHostingController(rootView: rootView)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
print("updateUI")
}
}
struct SwiftUIView19: View {
@State var isGreen: Bool = true
var body: some View {
ControllerView(isGreen: $isGreen) {
if isGreen {
MyView(rootView: AnyView(GreenView()))
} else {
MyView(rootView: AnyView(OrangeView()))
}
}
}
}
#Preview {
SwiftUIView19()
}
每个分支都隐式返回
类型MyView
不,它隐式返回
ViewBuilder.buildEither(first: ...)
和 ViewBuilder.buildEither(second: ...)
。这两个都返回 _ConditionalContent
。
ControllerView
不应强制视图类型为 MyView
。使其通用:
private struct ControllerView<Content: View>: View {
let rootView: () -> Content
@Binding var isGreen: Bool
init(isGreen: Binding<Bool>, @ViewBuilder rootView: @escaping () -> Content) {
self.rootView = rootView
self._isGreen = isGreen
}
...
}
如果出于某种原因您只需要
View
中的某些类型的 ControllerView
,我建议您编写自己的 ViewBuilder
版本,将所有内容委托给内置 ViewBuilder
,就像我在 here 所建议的那样.
并且
MyView
确实可以通用以避免AnyView
。这与ControllerView
的更改非常相似
private struct MyView<Content: View>: UIViewControllerRepresentable {
let rootView: Content
init(rootView: Content) {
self.rootView = rootView
print("init MyView")
}
...
}