简体   繁体   中英

How to force an explicit animation to occur in SwiftUI

I created this View modifier which animates a change in the offset of a view based on a boolean Binding and resets itself when the animation finishes (also resetting the boolean Binding).

struct OffsetViewModifier: AnimatableModifier {
    let amount: Double  // amount of offset
    @Binding var animate: Bool  // determines if the animation should begin
    
    private(set) var pct = 0.0  // percentage of the animation complete
    
    var animatableData: Double {
        get { animate ? 1.0 : 0.0 }
        set { pct = newValue }
    }
    
    func body(content: Content) -> some View {
        content
            .offset(x: amount * pct)
            .onChange(of: pct) { newValue in
                if newValue == 1.0 {  // If newValue is 1.0 that means animation is complete
                    withAnimation(.none) { animate = false }  // When animation completes, reset binding
                    // Since I don't want this to cause an animation, I wrap it with withAnimation(.none)
                }
            }
    }
}

I used this new modifier like this:

VStack {
    Text(tapped.description)
    Circle()
        .frame(width: 100, height: 100)
        .onTapGesture {
            tapped = true
        }
        .modifier(OffsetViewModifier(amount: 50, animate: $tapped))
        .animation(Animation.linear(duration: 3), value: tapped)
}

However, the withAnimation(.none) didn't work, and this view still takes 3 seconds to reset.

How do I force the explicit animation to occur and not the .linear(duration: 3) one?

Thanks in advance.

If I understood this correctly, what you should do is wrap tapped within withAnimation because the .animation is modifying the whole view like this. tapped is binded to animate, when you change animate's value in the modifier, you're changing the value of tapped, therefore, executing the linear animation

VStack {
    Text(tapped.description)
    Circle()
        .frame(width: 100, height: 100)
        .onTapGesture {
            withAnimation(.linear(duration: 3)) {
                tapped = true
            }
        }
        .modifier(OffsetViewModifier(amount: 50, animate: $tapped))
}

My personal advice is to avoid using.animation() because like I said before it will animate the entire view and will cause problems like this one

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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