繁体   English   中英

SwiftUI:动画文本颜色 - foregroundColor()

[英]SwiftUI: Animate Text color - foregroundColor()

我一直在尝试为 UI 的各个部分设置动画,但似乎您无法为 SwiftUI Text 的 foregroundColor 设置动画? 当状态发生变化时,我想平滑地切换某些文本的颜色。 如果我为 Text 的周围视图的背景颜色设置动画,这很好用,但前景色不起作用。 有没有人有幸为这样的变化制作动画? 不确定这是 Xcode beta 错误还是预期的功能......

Text(highlightedText)
    .foregroundColor(color.wrappedValue)
    .animation(.easeInOut)

// Error: Cannot convert value of type 'Text' to closure result type '_'

有一个更简单的方法,借用 Apple 的“Animating Views and Transitions”教程代码。 HikeGraph 中 GraphCapsule 的实例化证明了这一点。

虽然foregroundColor不能动画,但colorMultiply可以。 将前景色设置为白色并使用 colorMultiply 设置您想要的实际颜色。 从红色到蓝色的动画:

struct AnimateDemo: View {
    @State private var color = Color.red

    var body: some View {
        Text("Animate Me!")
            .foregroundColor(Color.white)
            .colorMultiply(self.color)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 1)) {
                    self.color = Color.blue
                }
        }
    }
}

struct AnimateDemo_Previews: PreviewProvider {
    static var previews: some View {
        AnimateDemo()
    }
}

SwiftUI 中有一个很好的协议,可以让你为任何东西设置动画。 即使是不可动画的东西! (如文本颜色)。 该协议称为 AnimatableModifier。

如果你想了解更多关于它的信息,我写了一篇完整的文章来解释它是如何工作的: https : //swiftui-lab.com/swiftui-animations-part3/

下面是一个关于如何完成这样一个视图的例子:

AnimatableColorText(from: UIColor.systemRed, to: UIColor.systemGreen, pct: flag ? 1 : 0) {
    Text("Hello World").font(.largeTitle)
}.onTapGesture {
    withAnimation(.easeInOut(duration: 2.0)) {
      self.flag.toggle()
    }
}

和实施:

struct AnimatableColorText: View {
    let from: UIColor
    let to: UIColor
    let pct: CGFloat
    let text: () -> Text

    var body: some View {
        let textView = text()

        // This should be enough, but there is a bug, so we implement a workaround
        // AnimatableColorTextModifier(from: from, to: to, pct: pct, text: textView)

        // This is the workaround
        return textView.foregroundColor(Color.clear)
            .overlay(Color.clear.modifier(AnimatableColorTextModifier(from: from, to: to, pct: pct, text: textView)))
    }

    struct AnimatableColorTextModifier: AnimatableModifier {
        let from: UIColor
        let to: UIColor
        var pct: CGFloat
        let text: Text

        var animatableData: CGFloat {
            get { pct }
            set { pct = newValue }
        }

        func body(content: Content) -> some View {
            return text.foregroundColor(colorMixer(c1: from, c2: to, pct: pct))
        }

        // This is a very basic implementation of a color interpolation
        // between two values.
        func colorMixer(c1: UIColor, c2: UIColor, pct: CGFloat) -> Color {
            guard let cc1 = c1.cgColor.components else { return Color(c1) }
            guard let cc2 = c2.cgColor.components else { return Color(c1) }

            let r = (cc1[0] + (cc2[0] - cc1[0]) * pct)
            let g = (cc1[1] + (cc2[1] - cc1[1]) * pct)
            let b = (cc1[2] + (cc2[2] - cc1[2]) * pct)

            return Color(red: Double(r), green: Double(g), blue: Double(b))
        }

    }
}

在此处输入图片说明

Text Color 属性在SwiftUIUIKit不可设置动画。 但是你可以像这样实现你需要的结果:

struct ContentView: View {

    @State var highlighted = false

    var body: some View {
        VStack {
            ZStack {
            // Highlighted State
            Text("Text To Change Color")
                .foregroundColor(.red)
                .opacity(highlighted ? 1 : 0)

            // Normal State
            Text("Text To Change Color")
                .foregroundColor(.blue)
                .opacity(highlighted ? 0 : 1)
            }
            Button("Change") {
                withAnimation(.easeIn) {
                    self.highlighted.toggle()
                }
            }
        }
    }
}

您可以将此功能封装在自定义View并在您喜欢的任何地方使用它。

不幸的是,您无法为文本颜色设置动画。 对于可以设置动画的属性,必须在要设置动画的状态变化周围放置withAnimation,如下所示:

struct ContentView: View {

    @State var size: CGFloat = 25.0

    var body: some View {
        VStack {
            Rectangle()
                .foregroundColor(.green)
                .frame(width: size, height: size)
            Spacer()
            Button("Tap me") {
                withAnimation(.easeIn) {
                    self.size += 5.0
                }
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM