【问题标题】:SwiftUI Text animation on opacity does not work不透明度上的 SwiftUI 文本动画不起作用
【发布时间】:2020-05-27 10:44:58
【问题描述】:

问题很简单:到底如何才能让Text 正确地制作动画?

struct ContentView: View {
    @State var foozle: String = ""

    var body: some View {
        VStack() {
            Spacer()

            Text(self.foozle)
                .frame(maxWidth: .infinity)
                .transition(.opacity)

            Button(action: {
                withAnimation(.easeInOut(duration: 2)) {
                    self.foozle = "uuuuuuuuu"
                }
            }) { Text("ugh") }

            Spacer()
        }.frame(width: 320, height: 240)
    }
}

问题:视图坚持做一些愚蠢的动画,其中文本被新文本替换,但被省略号截断,它慢慢地向宽度方向扩展,直到显示整个新文本。

当然,这不是关于不透明度的动画。这不是框架宽度问题,我已经通过绘制边框进行了验证。

这只是 SwiftUI 中另一个我必须处理的愚蠢错误,并祈祷有人修复它吗?

编辑:好的,感谢@Mac3n,我得到了这个灵感,它可以正常工作,即使它有点难看:

Text(self.foozle)
    .frame(maxWidth: .infinity)
    .opacity(op)

Button(action: {
    withAnimation(.easeOut(duration: 0.3)) {
        self.op = 0

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            self.foozle += "omo"

            withAnimation(.easeIn(duration: 0.3)) {
                self.op = 1
            }
        }
    }

}) {
    Text("ugh")
}

【问题讨论】:

    标签: swift macos cocoa swiftui


    【解决方案1】:

    如果您想在不透明度上制作动画,则需要更改文本元素的不透明度值。

    代码示例:

    @State private var textValue: String = "Sample Data"
    @State private var opacity: Double = 1
        var body: some View {
            VStack{
                Text("\(textValue)")
                    .opacity(opacity)
                Button("Next") {
                    withAnimation(.easeInOut(duration: 0.5), {
                        self.opacity = 0
                    })
                    self.textValue = "uuuuuuuuuuuuuuu"
                    withAnimation(.easeInOut(duration: 1), {
                        self.opacity = 1
                    })
                }
            }
        }
    

    【讨论】:

    • 这不太行;尽管 new 文本动画化了,但旧文本只是消失了。动画闭包可能在单独的线程中运行,AFAIK 没有办法链接动画,也没有完成回调......
    • 也许 AnimatableModifire 可以做到。检查此链接:swiftui-lab.com/swiftui-animations-part3
    • 这给了我找到解决方案的灵感,所以我会接受这个。谢谢!
    【解决方案2】:

    Transition 在视图出现/消失时工作。在您的用例中,没有这样的工作流程。

    这是一个使用不透明动画隐藏/取消隐藏文本的可能方法的演示:

    struct DemoTextOpacity: View {
        var foozle: String = "uuuuuuuuu"
        @State private var hidden = true
    
        var body: some View {
            VStack() {
                Spacer()
    
                Text(self.foozle)
                    .frame(maxWidth: .infinity)
                    .opacity(hidden ? 0 : 1)
    
                Button(action: {
                    withAnimation(.easeInOut(duration: 2)) {
                        self.hidden.toggle()
                    }
                }) { Text("ugh") }
    
                Spacer()
            }.frame(width: 320, height: 240)
        }
    }
    

    【讨论】:

    • 我的用例并不是真正隐藏/取消隐藏文本,而是 Text 的值需要更改,我希望它能够顺利更改。就这样。下面的另一个答案尝试手动将不透明度设置为 0,更改文本,然后将其设置回 1,但它无法正常工作。
    • @zhiayang, Opacity 因为我们Transition 是视图(在您的情况下为文本)的功能,而不是在您的情况下为String 的模型。如果您为更改字符串设置动画,SwfitUI 会逐个字母地为字符串的外观设置动画。
    • 是的,我想这是有道理的。这不是很直观。我找到了一个解决方案,我在问题中对其进行了编辑。谢谢!
    【解决方案3】:

    问题在于 SwiftUI 将 Text 视图视为同一个视图。您可以使用视图上的 .id() 方法来设置它。在这种情况下,我只是将值设置为文本本身的哈希值,因此如果您更改文本,整个视图将被替换。

    struct ContentView: View {
        @State var foozle: String = ""
    
        var body: some View {
            VStack() {
                Spacer()
    
                Text(self.foozle)
                    .id(self.foozle.hashValue)
                    .frame(maxWidth: .infinity)
                    .transition(.opacity)
    
                Button(action: {
                    withAnimation(.easeInOut(duration: 2)) {
                        self.foozle = "uuuuuuuuu"
                    }
                }) { Text("ugh") }
    
                Spacer()
            }.frame(width: 320, height: 240)
        }
    }
    

    【讨论】:

    • 哦,知道这很有趣!稍后我会尝试一下,但感谢您的回答!
    • 更加优雅,并且是问题的实际解决方案,而不是一些 hacky 解决方法。这应该是公认的答案。
    猜你喜欢
    • 2014-06-28
    • 2014-11-02
    • 1970-01-01
    • 2018-03-04
    • 2012-11-04
    • 2012-04-01
    • 2010-09-25
    • 2019-02-06
    • 2017-07-25
    相关资源
    最近更新 更多