Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Changing translation of a DragGesture swift

I am working with a slider and dealing with translation. Once the slider performs an action, I mock an api call and then on completion the image is unlocked but now I would like to return the slider to the original position once the api call is completed. Here is what the slider looks like in code.

struct DraggingComponent: View {
    
    @Binding var isLocked: Bool
    @Binding var isLoading: Bool
    let maxWidth: CGFloat
    
    @State private var width = CGFloat(50)
    private let minWidth = CGFloat(50)
    
    init(isLocked: Binding<Bool>, isLoading: Binding<Bool>, maxWidth: CGFloat) {
        _isLocked = isLocked
        self._isLoading = isLoading
        self.maxWidth = maxWidth
    }
    
    var body: some View {
        RoundedRectangle(cornerRadius: 16)
            .fill(Color.black)
            .opacity(width / maxWidth)
            .frame(width: width)
            .overlay(
                Button(action: { }) {
                    ZStack {
                        image(name: "lock", isShown: isLocked)
                        progressView(isShown: isLoading)
                        image(name: "lock.open", isShown: !isLocked && !isLoading)
                    }
                    .animation(.easeIn(duration: 0.35).delay(0.55), value: !isLocked && !isLoading)
                }
                    .buttonStyle(BaseButtonStyle())
                    .disabled(!isLocked || isLoading),
                alignment: .trailing
            )
        
            .simultaneousGesture(
                DragGesture()
                    .onChanged { value in
                        guard isLocked else { return }
                        if value.translation.width > 0 {
                            width = min(max(value.translation.width + minWidth, minWidth), maxWidth)
                        }
                    }
                    .onEnded { value in
                        guard isLocked else { return }
                        if width < maxWidth {
                            width = minWidth
                            UINotificationFeedbackGenerator().notificationOccurred(.warning)
                            
                        } else {
                            UINotificationFeedbackGenerator().notificationOccurred(.success)
                            withAnimation(.spring().delay(0.5)) {
                                
                                isLocked = false
                                
                            }
                            
                        }
                    }
            )
            .animation(.spring(response: 0.5, dampingFraction: 1, blendDuration: 0), value: width)
        
    }
    
    private func image(name: String, isShown: Bool) -> some View {
        Image(systemName: name)
            .font(.system(size: 20, weight: .regular, design: .rounded))
            .foregroundColor(Color.black)
            .frame(width: 42, height: 42)
            .background(RoundedRectangle(cornerRadius: 14).fill(.white))
            .padding(4)
            .opacity(isShown ? 1 : 0)
            .scaleEffect(isShown ? 1 : 0.01)
        
        
    }
    
    private func progressView(isShown: Bool) -> some View {
        ProgressView()
            .progressViewStyle(.circular)
            .tint(.white)
            .opacity(isShown ? 1 : 0)
            .scaleEffect(isShown ? 1 : 0.01)
    }
    
}

Where it is used:

@State private var isLocked = true
@State private var isLoading = false

GeometryReader { geometry in
    ZStack(alignment: .leading) {
        BackgroundComponent()
        DraggingComponent(isLocked: $isLocked, isLoading: $isLoading, maxWidth: geometry.size.width)
    }
}
.frame(height: 50)
.padding()
.padding(.bottom, 20)
.onChange(of: isLocked) { isLocked in
    guard !isLocked else { return }
    simulateRequest()
}

private func simulateRequest() {
    isLoading = true
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        isLoading = false
    }
}

How can I get the translation back to the initial position.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Pull your width @State up into the containing view and pass it on as @Binding. After simulateRequest set it to its initial state.

In your DraggingComponent use

struct DraggingComponent: View {
    @Binding var width: CGFloat
    .....

in the View that contains DraggingComponent:

@State private var width = CGFloat(50)

and:

.onChange(of: isLocked) { isLocked in
        guard !isLocked else { return }
        simulateRequest()
        self.width = CGFloat(50) //reset it here probably with animation
    }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading