简体   繁体   English

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

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

I've been trying to work on animating various parts of the UI, but it seems as though you can't animate a SwiftUI Text's foregroundColor?我一直在尝试为 UI 的各个部分设置动画,但似乎您无法为 SwiftUI Text 的 foregroundColor 设置动画? I want to switch the color of some text smoothly when a state changes.当状态发生变化时,我想平滑地切换某些文本的颜色。 This works fine if I animate the background color of the Text's surrounding view, but foreground color does not work.如果我为 Text 的周围视图的背景颜色设置动画,这很好用,但前景色不起作用。 Has anyone had any luck animating a change like this?有没有人有幸为这样的变化制作动画? Unsure if this is an Xcode beta bug or it's intended functionality...不确定这是 Xcode beta 错误还是预期的功能......

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

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

There is a much easier way, borrowing from Apple's "Animating Views and Transitions" tutorial code.有一个更简单的方法,借用 Apple 的“Animating Views and Transitions”教程代码。 The instantiation of GraphCapsule in HikeGraph demonstrates this. HikeGraph 中 GraphCapsule 的实例化证明了这一点。

While foregroundColor cannot be animated, colorMultiply can.虽然foregroundColor不能动画,但colorMultiply可以。 Set the foreground color to white and use colorMultiply to set the actual color you want.将前景色设置为白色并使用 colorMultiply 设置您想要的实际颜色。 To animate from red to blue:从红色到蓝色的动画:

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()
    }
}

There is a nice protocol in SwiftUI that let you animate anything. SwiftUI 中有一个很好的协议,可以让你为任何东西设置动画。 Even things that are not animatable!即使是不可动画的东西! (such as the text color). (如文本颜色)。 The protocol is called AnimatableModifier.该协议称为 AnimatableModifier。

If you would like to learn more about it, I wrote a full article explaining how this works: https://swiftui-lab.com/swiftui-animations-part3/如果你想了解更多关于它的信息,我写了一篇完整的文章来解释它是如何工作的: https : //swiftui-lab.com/swiftui-animations-part3/

Here's an example on how you can accomplish such a view:下面是一个关于如何完成这样一个视图的例子:

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()
    }
}

And the implementation:和实施:

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))
        }

    }
}

在此处输入图片说明

Color property of Text is not animatable in SwiftUI or UIKit . Text Color 属性在SwiftUIUIKit不可设置动画。 BUT YOU CAN achieve the result you need like this:但是你可以像这样实现你需要的结果:

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()
                }
            }
        }
    }
}

You can encapsulate this functionality in a custom View and use it anywhere you like.您可以将此功能封装在自定义View并在您喜欢的任何地方使用它。

Unfortunately you cannot animate text colour. 不幸的是,您无法为文本颜色设置动画。 For properties you can animate, you have to put withAnimation around the change of state you want to animate, like this: 对于可以设置动画的属性,必须在要设置动画的状态变化周围放置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