Home > Mobile >  Changing translation of a DragGesture swift
Changing translation of a DragGesture swift

Time:09-02

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.

CodePudding user response:

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
    }
  • Related