【问题标题】:Why SwiftUI-transition does not work as expected when I use it in UIHostingController?为什么当我在 UIHostingController 中使用 SwiftUI-transition 时,它不能按预期工作?
【发布时间】:2020-11-28 14:37:03
【问题描述】:

我正在尝试为需要显示日期的视图进行良好的过渡。我为视图提供了一个 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
    }
}

结果,新标签没有动画,而是插入到它的最终位置,而旧标签正在动画出来:

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

【问题讨论】:

    标签: swiftui swiftui-animation


    【解决方案1】:

    不同主机控制器之间的状态不能很好地运行(不清楚这是限制还是错误,只是经验观察)。

    解决方案是在托管视图中嵌入依赖状态。使用 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")
                 }
            }
        }
    }
    

    注意:您也可以尝试基于 ObservableObject/ObservedObject 的视图模型 - 该模式具有不同的生命周期。

    【讨论】:

    • 这是正确的!但是对于我来说,将状态保留在视图中并不是一种选择,因为它来自外部,不像示例中那样。我会玩 ObservableObject 寿!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 2020-03-05
    • 1970-01-01
    相关资源
    最近更新 更多