1 year ago

#57865

test-img

nickcoding2

Sliding card not showing transition from withAnimation { } block

so I have a sliding card located at the bottom of the page. When it appears, it starts with the top of edge of the card at about halfway up the screen. I want to make it so that when I tap it or swipe down, it dismisses by animating a transition of the card to the bottom edge of the screen. The problem I'm running into is this. When I'm running the withAnimation { } block, the card is dismissing immediately (instantly disappearing) instead of animating the change by moving off the screen smoothly. How can I fix this?

struct ContentView: View {
    @ObservedObject var appState: AppState = AppState()
    var body: some View {
        
        ZStack {
            Color.gray
            Text("Main View")
            SlideOverView(appState: appState, content: {
                VStack {
                    Text("Slide Over View")
                    Spacer()
                }
            })
        }
    }
}

class AppState: NSObject, ObservableObject {
    
    @Published var showCard: Bool = false
}

struct SlideOverView<Content> : View where Content : View {
    @ObservedObject var appState: AppState
    var content: () -> Content
    
    init(appState: AppState, content: @escaping () -> Content) {
        self.appState = appState
        self.content = content
    }
     
    public var body: some View {
        ModifiedContent(content: self.content(), modifier: CardView(appState: appState))
    }
}


struct CardView: ViewModifier {
    @ObservedObject var appState: AppState
    @State private var dragging = false
    @GestureState private var dragTracker: CGSize = CGSize.zero
    
    func body(content: Content) -> some View {
        let position: CGFloat = UIScreen.main.bounds.height * 0.4
        return ZStack(alignment: .top) {
            if appState.showCard {
                ZStack(alignment: .top) {
                    RoundedRectangle(cornerRadius: 2.5)
                        .frame(width: 40, height: 5.0)
                        .foregroundColor(Color.secondary)
                        .padding(10)
                    content.padding(.top, 30)
                }.transition(.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .bottom)))
                .frame(minWidth: UIScreen.main.bounds.width)
                .scaleEffect(x: 1, y: 1, anchor: .center)
                .background(Color.white)
                .cornerRadius(15)
            }
        }
        .offset(y:  max(0, position + self.dragTracker.height))
        .animation({
            Animation.interpolatingSpring(stiffness: 250.0, damping: 40.0, initialVelocity: 5.0)
        }())
        .gesture(DragGesture()
                    .updating($dragTracker) { drag, state, transaction in state = drag.translation }
                    .onChanged {_ in  dragging = true }
                    .onEnded(onDragEnded))
        .onTapGesture {
            let low: CGFloat = UIScreen.main.bounds.height * 0.4
            if position == low {
                withAnimation {
                    appState.showCard = false
                }
            }
        }
    }
    
    private func onDragEnded(drag: DragGesture.Value) {
        dragging = false
        let dragDirection = drag.predictedEndLocation.y - drag.location.y
        if dragDirection > 0 {
            withAnimation {
                appState.showCard = false
            }
        }
    }
}

swift

animation

swiftui

gesture

uiswipegesturerecognizer

0 Answers

Your Answer

Accepted video resources