'Offset doesn't reset after onTapGesture - SwiftUI

Im trying to create a card that slides when it is tapped on and then goes back to original position without tapping again the .onEnded() function of tap gesture isn't working

This is the test code

struct ContentView: View {

@State var tapped = false
var body: some View {
    VStack {
        ZStack {
            Rectangle()
                .fill(Color.green)
                .frame(height: 300)
            
            Rectangle()
                .fill(Color.red)
                .frame(width: 290, height: 64)
                .offset(y: tapped ? 118 : 0)
                .onTapGesture {
                    self.tapped.toggle()
            }
            .animation(.easeInOut)
        }
        
        Spacer()
    }.edgesIgnoringSafeArea(.all)
}

}



Solution 1:[1]

Applied properties does not reset magically by themselves - you need to change them as/when needed.

Here is simplest possible solution. Tested with Xcode 11.4 / iOS 13.4

demo

var body: some View {
    VStack {
        ZStack {
            Rectangle()
                .fill(Color.green)
                .frame(height: 300)

            Rectangle()
                .fill(Color.red)
                .frame(width: 290, height: 64)
                .offset(y: tapped ? 118 : 0)
                .onTapGesture {
                    self.tapped.toggle()
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        self.tapped.toggle()
                    }
            }
            .animation(Animation.easeInOut(duration: 0.5))
        }

        Spacer()
    }.edgesIgnoringSafeArea(.all)
}

backup

Solution 2:[2]

Solved it using a delay in explicit animation. A repeat-while cycle allows you to specify how many times the rectangle will be bounced:

struct ContentView: View {

@State var tapped = false
    @State var countOfBounce: Double = 0
    @State var addDelay: Double = 0

var body: some View {
    VStack {
        ZStack {
            Rectangle()
                .fill(Color.green)
                .frame(height: 300)

            Rectangle()
                .fill(Color.red)
                .frame(width: 290, height: 64)
                .offset(y: tapped ? 118 : 0)
                .onTapGesture {
                    repeat {
                    withAnimation(.linear(duration: 0.5).delay(0 + addDelay)){
                    self.tapped.toggle()
                    }
                    countOfBounce += 1
                    addDelay += 0.5
                } while countOfBounce < 2
                    countOfBounce = 0
                    addDelay = 0
            }
        }
        Spacer()
        }.edgesIgnoringSafeArea(.all)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Biclops