SwiftUI flash animation

I'm struggling to implement a flash animation in SwiftUI.

Generally animations animate from one value to another. I'd like to animate from normal to the flashed state and then back to normal, each time the data shown by the view changes. The "flashed state" could be transparent, or a white background, or it could be a scale change for a pulse effect, or something.

Example:

struct MyView: View
{
    let value: String;

    var body: some View {
        ZStack {
            Capsule() .fill(Color.green);
            Text(value);
        }
    };
};

Each time value changes, I'd like the colour of the capsule to quickly animate from green to white and back to green.

I feel this should be easy - am I missing something?

For bonus points:

  • I'd like the Text to change to its new value at the midpoint of the animation, i.e. when the white text is invisible on the white background.

  • I'd like to get the flash effect whenever I have a new value even if the new value is equal to the old value, if you see what I mean.

You want to represent that using PhaseAnimator. It allows you define a set of phases to create an animated transition based on those events.

For example:

struct TwoPhaseAnimationView: View {
    var emoji: String
    @State private var likeCount = 1
    
    var body: some View {
        EmojiView(emoji: emoji)
            .phaseAnimator([false, true], trigger: likeCount) { content, phase in
                content.offset(y: phase ? -40.0 : 0.0)
            } animation: { phase in
                phase ? .bouncy : .default
            }
            .onTapGesture {
                likeCount += 1
            }
    }
}

In this example, the following code increments the state variable likeCount each time a person taps the emoji. The code uses likeCount as the value that the phase animator observes for changes. Now whenever someone taps the emoji, it moves up and returns to its original position. It also applies a bouncy animation when the phase is true; otherwise, it applies the default animation:

I suggest you review [Controlling the timing and movements of your animations] (https://developer.apple.com/documentation/swiftui/controlling-the-timing-and-movements-of-your-animations) sample project and the article as well. It contains more detailed examples .

Thanks, I think I worked that out about the same time you posted. I currently have:

                PhaseAnimator([false,true], trigger: some_variable) { phase in
                    Capsule()
                        .fill(some_colour)
                        .opacity(phase ? 0 : 1);
                };

I've not yet worked out how to set the animation duration (etc.) with this form, though I've not really looked yet.

I've also not yet looked at how to delay the change of the Text (in my original post) to the midpoint of the flash. I think I need a "non-animation", i.e. an animation that instantly changes from the old to the new value, with a suitable delay. Or something.

I now have something like this:

struct MyView: View
{
    let value: String;

    let flash_duration = 0.1;

    var body: some View {
        ZStack {
            Capsule()
                .phaseAnimator([false,true], trigger: value) { content, phase in
                    content .foregroundStyle(phase ? .primary : .green);  // Note not .fill
                } animation: {
                    .linear(duration: flash_duration/2)  // I wonder what the preferred curve is?
                }
            Text(value)
                .animation(.linear(duration: 0) .delay(flash_duration/2), value: value);
        }
    };
};
SwiftUI flash animation
 
 
Q