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