Home > front end >  SwiftUI ViewModifier animation not showing properly everytime
SwiftUI ViewModifier animation not showing properly everytime

Time:07-23

I have created a ViewModifier that adds a icon to the right of a its content, the way I want the icon to appear is by animating the .clipShape() modifier from -50 to 0, the problem is that when appearing the first time, it just pops out with no animation and the same thing happens when disappearing for the last time. At the bottom you'll find a video demonstration

My ViewModifier so far

extension View {
    func addRightIcon(icon: Image, show: Bool) -> some View {
        return modifier(RightIconModifier(icon: icon, show: show))
    }
}

struct RightIconModifier: ViewModifier {
    
    var icon: Image
    private var iconMask: Int = 0

    init(icon: Image, show: Bool) {
        self.icon = icon
        withAnimation(Animation.interpolatingSpring(stiffness: 170, damping: 15).delay(2.5)) {
            iconMask = show ? 0 : -50
        }
    }
    
    func body(content: Content) -> some View {
        ZStack {
            content
                .overlay(rightIcon)
        }
    }
    
    var rightIcon: some View {
        icon
            .font(.system(size: 25))
            .foregroundColor(.black)
            .frame(maxWidth: .infinity,
                   maxHeight: .infinity,
                   alignment: .trailing)
            .padding()
            .clipShape(Rectangle().offset(x: CGFloat(iconMask)))
    }
}

This would be a short version of how I'm using it, hopefully you get an idea to make it work

TextField(placeholder, text: $text).addRightIcon(icon: Image(systemName: "checkmark"), show: isTextValid)

var isTextValid: Bool {
        if !text.isEmpty {
            let validation = NSPredicate(format: "SELF MATCHES %@", "[’a-zA-Z]{3,20}")
            let validated = validation.evaluate(with: text)
            return validated
        }
        return false
    }

enter image description here

struct RightIconModifier: ViewModifier {
    
    var icon: Image
    var show: Bool    // << injected changes

    func body(content: Content) -> some View {
        ZStack {
            content
                .overlay(rightIcon)
        }
    }
    
    var rightIcon: some View {
        icon
            .font(.system(size: 25))
            .foregroundColor(.black)
            .frame(maxWidth: .infinity,
                   maxHeight: .infinity,
                   alignment: .trailing)
            .padding()
            .clipShape(Rectangle().offset(x: CGFloat(show ? 0 : -50))) // << switch is here !!
            .animation(.easeIn(duration: 1), // << simplified for testing
                       value: show)
    }
}

Test module on GitHub

  • Related