提问人:Amirca 提问时间:11/10/2023 最后编辑:Amirca 更新时间:11/11/2023 访问量:43
如何强制创建新的 UIViewControllerRepresentable |更新 makeUIViewController 上的视图
How to force to create a new UIViewControllerRepresentable | updating views on makeUIViewController
问:
我在创建新视图时遇到了问题,因为该方法仅在 中运行一次,从而阻止了对新视图的更新。在保持内部隐私的同时修改此代码的最佳方法是什么?UIViewControllerRepresentable
makeUIViewController
UIViewControllerRepresentable
MyView
ControllerView
private struct ControllerView<Content: View>: View {
struct MyView<ContentM: View>: UIViewControllerRepresentable {
let rootView: ContentM
init(rootView: ContentM) {
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")
}
}
let rootView: () -> Content
@Binding var isGreen: Bool
init(isGreen: Binding<Bool>,@ViewBuilder rootView: @escaping () -> Content) {
self.rootView = rootView
self._isGreen = isGreen
}
var body: some View {
ZStack {
MyView(rootView: 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()}
}
struct SwiftUIView21: View {
@State var isGreen: Bool = true
var body: some View {
ControllerView(isGreen: $isGreen) {
if isGreen {
GreenView()
} else {
OrangeView()
}
}
}
}
#Preview {
SwiftUIView21()
}
答:
1赞
Sweeper
11/10/2023
#1
虽然不叫,但就是。您可以更改其中显示的视图。makeUIViewController
updateUIViewController
UIHostingController
func makeUIViewController(context: Context) -> UIHostingController<ContentM> {
print("makeUI")
return UIHostingController(rootView: rootView)
}
func updateUIViewController(_ uiViewController: UIHostingController<ContentM>, context: Context) {
uiViewController.rootView = rootView
print("updateUI")
}
请注意,当您在两个视图之间切换时,这将破坏您想要执行的任何动画。SwiftUI 无法制作动画。uiViewController.rootView = rootView
或者,您可以在每次切换发生时更改 的 id:MyView
MyView(rootView: rootView()).id(isGreen)
这将在每次更改视图时重新创建一个新视图,并可以对更改进行动画处理。然而,这只对两个 s 之间的变化进行了动画处理,这恰好看起来类似于在 和 之间切换的动画(都是交叉淡入淡出)。如果您有其他动画,例如对某物的比例进行动画处理:UIHostingController
MyView
OrangeView
GreenView
Text("Foo").scaleEffect(isGreen ? 1 : 2)
然后动画仍将是交叉淡入淡出,而不是缩放动画。
我发现的第三种方法是使用包装器包装 ,然后将其放入 .@Observable
Bool
Environment
@Observable
class BoolWrapper: ExpressibleByBooleanLiteral {
var bool: Bool
required init(booleanLiteral value: Bool) {
bool = value
}
}
private struct ControllerView<Content: View>: View {
struct MyView<ContentM: View>: UIViewControllerRepresentable {
let rootView: () -> ContentM
init(@ViewBuilder rootView: @escaping () -> ContentM) {
self.rootView = rootView
print("init MyView")
}
func makeUIViewController(context: Context) -> UIHostingController<ContentM> {
print("makeUI")
return UIHostingController(rootView: rootView())
}
func updateUIViewController(_ uiViewController: UIHostingController<ContentM>, context: Context) {
print("updateUI")
}
}
let rootView: () -> Content
let isGreen: BoolWrapper
init(isGreen: BoolWrapper,@ViewBuilder rootView: @escaping () -> Content) {
self.rootView = rootView
self.isGreen = isGreen
}
var body: some View {
ZStack {
MyView(rootView: rootView)
Button {
withAnimation {
isGreen.bool.toggle()
}
} label: {
Text("Change")
}
}
}
}
struct ContentView: View {
@State var isGreen: BoolWrapper = true
var body: some View {
ControllerView(isGreen: isGreen) {
GreenOrangeWrapper().environment(isGreen)
}
}
}
struct GreenOrangeWrapper: View {
@Environment(BoolWrapper.self) var boolWrapper
var body: some View {
if boolWrapper.bool {
GreenView()
} else {
OrangeView()
}
}
}
现在动画都保留了。
评论
0赞
Amirca
11/10/2023
感谢您注意到这个习俗。但是,以这种方式使代码泛型会导致在按下更改按钮时视图不会更新,因为调用仅发生一次。因此,我能想到的唯一方法就是传递给 .你有什么方法吗?ViewBuilder
makeUIViewController
MyView
ControllerView
0赞
Amirca
11/10/2023
你是对的。该代码适用于此泛型。让我解释一下。我试图在我的包裹中保留内部。所以只是可以访问它并把而不是.在本例中,视图未更新(因为调用了一次)。那么有没有办法保持 ControllerView 的私密性呢?MyView
ControllerView
ConterollerView
MyView(rootView: rootView())
rootView()
makeUIViewController
0赞
Amirca
11/10/2023
很抱歉造成混乱。我更新了代码。
0赞
Sweeper
11/10/2023
@Amirca 请参阅编辑。我想到了两种方法。两者都不是很好。要让 SwiftUI 认识到 UIKit 代码的“间隙”发生了变化,这真的很困难。如果你允许知道,那就容易多了。MyView
isGreen
评论