当我在UIHostingController中使用SwiftUI转换时,为什么它不能按预期工作?

当我在UIHostingController中使用SwiftUI转换时,为什么它不能按预期工作?,swiftui,swiftui-animation,Swiftui,Swiftui Animation,我正在尝试为需要显示日期的视图提供一个良好的转换。我给视图指定了一个ID,这样SwiftUI就知道它是一个新标签,并通过转换为它设置动画。以下是精简版,没有格式化程序和样式,持续时间较长,以便更好地可视化: struct ContentView: View { @State var date = Date() var body: some View { VStack { Text("\(date.description)&quo

我正在尝试为需要显示日期的视图提供一个良好的转换。我给视图指定了一个ID,这样SwiftUI就知道它是一个新标签,并通过转换为它设置动画。以下是精简版,没有格式化程序和样式,持续时间较长,以便更好地可视化:

struct ContentView: View {
    @State var date = Date()

    var body: some View {
        VStack {
            Text("\(date.description)")
                .id("DateLabel" + date.description)
                .transition(.slide)
                .animation(.easeInOut(duration: 5))

            Button(action: { date.addTimeInterval(24*60*60) }) {
                Text("Click")
            }
        }
    }
}
结果,它按预期工作,旧标签正在制作动画,新标签正在制作动画:

但一旦我将其包装到UIHostingController中:

struct ContentView: View {
    @State var date = Date()

    var body: some View {
        AnyHostingView {
            VStack {
                Text("\(date.description)")
                    .id("DateLabel" + date.description)
                    .transition(.slide)
                    .animation(.easeInOut(duration: 5))

                Button(action: { date.addTimeInterval(24*60*60) }) {
                    Text("Click")
                }
            }
        }
    }
}

struct AnyHostingView<Content: View>: UIViewControllerRepresentable {
    typealias UIViewControllerType = UIHostingController<Content>
    let content: Content

    init(content: () -> Content) {
        self.content = content()
    }

    func makeUIViewController(context: Context) -> UIHostingController<Content> {
        let vc = UIHostingController(rootView: content)
        return vc
    }

    func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) {
        uiViewController.rootView = content
    }
}
struct ContentView:View{
@状态变量日期=日期()
var body:一些观点{
AnyHostingView{
VStack{
文本(“\(日期说明)”)
.id(“日期标签”+日期说明)
.transition(.slide)
.animation(.easeInOut(持续时间:5))
按钮(操作:{date.addTimeInterval(24*60*60)}){
文本(“单击”)
}
}
}
}
}
结构AnyHostingView:UIViewControllerRepresentable{
typealias UIViewControllerType=UIHostingController
让内容:内容
初始化(内容:()->内容){
self.content=content()
}
func makeUIViewController(上下文:context)->UIHostingController{
让vc=UIHostingController(rootView:content)
返回vc
}
func updateUIViewController(uViewController:UIHostingController,上下文:上下文){
uiViewController.rootView=内容
}
}
结果,新标签未在中设置动画,而只是插入到其最终位置,而旧标签正在设置动画:


我有更复杂的主机控制器,但这说明了这个问题。我更新主机控制器视图的方式是否有问题,或者这是SwiftUI中的一个bug,还是其他什么?

状态在不同主机控制器之间运行不正常(不清楚这是限制还是bug,只是经验观察)

解决方案是在宿主视图中嵌入依赖状态。使用Xcode 12.1/iOS 14.1进行测试

struct ContentView: View {
    var body: some View {
        AnyHostingView {
            InternalView()
        }
    }
}

struct InternalView: View {
    @State private var date = Date()   // keep relative state inside
    var body: some View {
        VStack {
             Text("\(date.description)")
                  .id("DateLabel" + date.description)
                  .transition(.slide)
                  .animation(.easeInOut(duration: 5))

             Button(action: { date.addTimeInterval(24*60*60) }) {
                  Text("Click")
             }
        }
    }
}

注意:您还可以使用基于
observeObject/ObservedObject
的视图模型进行实验-该模式具有不同的生命周期。

这是正确的!但对于我来说,将状态保留在视图中不是一个选项,因为它来自外部,不像示例中那样。我将与ObservieObject tho一起玩!谢谢