首页 > 解决方案 > 使用自定义过渡和自定义标识符时 SwiftUI 系统布局中断

问题描述

我在 Xcode 12.5.1 上的 SwiftUI 系统布局存在问题在文本视图上,我使用的是基于自定义 ViewModifiers 的自定义转换()。此外,我还使用了一个自定义的 id(),它允许我告诉系统这个 Text View 是不一样的,因此会触发一个过渡动画。

在视图上使用这两个修饰符时,其父级和内容本身不尊重系统布局的预期行为。您可以在此视频中确切看到发生了什么

预期行为 预期行为

实际行为 实际行为

这是我的示例项目代码,您可以自己测试:

import SwiftUI

struct ContentView: View {
    private let contentArray: [String] = ["QWEQWE", "ASDASD", "TOTO", "FOO", "BAR"]
    @State private var content: String = "content"
    var body: some View {
        VStack {
            VStack {
                Text(self.content)
                    // commenting either the transition modifier, or the id modifier, make the system layout work as expected. The problem comes from using both at the same time
                    .transition(.customTransition)
                    .id(self.content)
            }
            .background(Color.blue)
            Button("action") {
                guard let newValue = self.contentArray.randomElement() else {
                    print("Failed to get a random element from property contentArray")
                    return
                }
                withAnimation {
                    self.content = newValue
                }
            }
        }
        .background(Color.green)
    }
}

extension AnyTransition {
    static var customTransition: AnyTransition {
        // uncomment the following line make the system layout work as expected. The problem comes from AnyTransition.modifier(active:identity:)
//        return AnyTransition.slide.combined(with: .opacity)
        let outAnimation = AnyTransition.modifier(active: CustomTrailingOffset(percent: 1), identity: CustomTrailingOffset(percent: 0)).combined(with: .opacity)
        let inAnimation = AnyTransition.modifier(active: CustomLeadingOffset(percent: 1), identity: CustomLeadingOffset(percent: 0)).combined(with: .opacity)
        return AnyTransition.asymmetric(insertion: inAnimation, removal: outAnimation)
    }
}

struct CustomLeadingOffset: ViewModifier {
    var percent: CGFloat = 0
    func body(content: Content) -> some View {
        GeometryReader { geo in
            content.offset(CGSize(width: -geo.size.width*self.percent, height: 0.0))
        }
    }
}

struct CustomTrailingOffset: ViewModifier {
    var percent: CGFloat = 0
    func body(content: Content) -> some View {
        GeometryReader { geo in
            content.offset(CGSize(width: geo.size.width*self.percent, height: 0.0))
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewLayout(.device)
            .previewDevice("iPhone 12")
    }
}

在 Xcode 12.5.1 上测试

在我的研究过程中,我没有发现任何关于这种行为的信息,不是在博客文章中,不是在论坛上,也不是在官方文档中,这就是我在这里发布这个问题的原因,以防万一有人遇到这个问题,知道它为什么会发生,或者知道解决方案。我已经同时向 Apple 填写了一个雷达 (FB9605660),但我不确定我是否会被告知他们的结论。

标签: iosswiftlayoutswiftuitransition

解决方案


推荐阅读