3

I would like to drag a slider and of course have it slide as well. I can do one or the other, but I cannot do both. How can I drag and have a working slider?

I also tried to find a way to remove a gesture, but I could not find a way to do that. Also tried the "Sequenced Gesture States" code from Apple "Composing SwiftUI Gestures" docs, and introduce a flag to turn the dragging on/off with same results, drag or slide not both.

I also tried to put the slider in a Container (VStack) and attach the drag gesture to that, but that did not work either.

import SwiftUI

struct ContentView: View {
@State var pos = CGSize.zero
@State var acc = CGSize.zero
@State var value = 0.0

var body: some View {
    let drag = DragGesture()
        .onChanged { value in
            self.pos = CGSize(width: value.translation.width + self.acc.width, height: value.translation.height + self.acc.height)
    }
    .onEnded { value in
        self.pos = CGSize(width: value.translation.width + self.acc.width, height: value.translation.height + self.acc.height)
        self.acc = self.pos
    }

    return Slider(value: $value, in: 0...100, step: 1)
        .frame(width: 250, height: 40, alignment: .center)
        .overlay(RoundedRectangle(cornerRadius: 25).stroke(lineWidth: 2).foregroundColor(Color.black))
        .offset(x: self.pos.width, y: self.pos.height)
        .simultaneousGesture(drag, including: .all)  // tried .none .gesture, .subviews
        // also tried .gesture(flag ? nil : drag)
}
}

With "simultaneousGesture" I was expecting to have both gestures operating at the same time.

  • I'm sorry, but I can't understand how a "dragging slider" works. The concept of a slider - no matter the language - implies that dragging is working the slider. Could you give an example? Preferable using `UIKit`? Since you tagged this SwiftUI, I've found that many times asking for an example using `UIKit1 makes things more clearer for me. –  Aug 24 '19 at 02:35
  • the idea here is to be able to change the slider position on the screen (drag it around), like if you were to drag an object around the screen. That is what the code above does. However, when this dragging around the screen stops I want to be able to use the slider knob to change the slider value, this is what I call slide in my question. – workingdog support Ukraine Aug 24 '19 at 02:45

1 Answers1

6

This is working. Basically I needed to set the flag in an outside observable object for it to update the view so that it could take effect. When the value changes the flag is set to false, but then after a tenth of a second it becomes draggable. Working pretty seamlessly.

struct ContentView: View {
    @State var pos = CGSize.zero
    @State var acc = CGSize.zero
    @State var value = 0.0

    @ObservedObject var model = Model()

    var body: some View {
        let drag = DragGesture()
            .onChanged { value in
                self.pos = CGSize(width: value.translation.width + self.acc.width, height: value.translation.height + self.acc.height)
        }
        .onEnded { value in
            self.pos = CGSize(width: value.translation.width + self.acc.width, height: value.translation.height + self.acc.height)
            self.acc = self.pos
        }

        return VStack {
            Slider(value: $value, in: 0...100, step: 1) { _ in
                self.model.flag = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                    self.model.flag = true
                }
            }
        }
        .frame(width: 250, height: 40, alignment: .center)
        .overlay(RoundedRectangle(cornerRadius: 25).stroke(lineWidth: 2).foregroundColor(Color.black))
        .offset(x: self.pos.width, y: self.pos.height)
        .gesture(model.flag == true ? drag : nil)
    }
}

class Model: ObservableObject {
    @Published var flag = false
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
MScottWaller
  • 3,321
  • 2
  • 24
  • 47