|
import SwiftUI |
|
import PlaygroundSupport |
|
|
|
class Model: ObservableObject { |
|
@Published var value: Double = 5.0 |
|
} |
|
|
|
struct RepeatButton: View { |
|
private let title: String |
|
private let systemImage: String |
|
private let interval: TimeInterval |
|
private let action: () -> Void |
|
|
|
@State private var timer: Timer? = nil |
|
|
|
init(_ title: String, systemImage: String, interval: TimeInterval = 0.4, action: @escaping () -> Void) { |
|
self.title = title |
|
self.systemImage = systemImage |
|
self.interval = interval |
|
self.action = action |
|
} |
|
|
|
var body: some View { |
|
Label(title, systemImage: systemImage) |
|
.padding(8.0) |
|
.background(Color.black.brightness(timer != nil ? 0.60 : 0.50)) |
|
.cornerRadius(8.0) |
|
.gesture(makeGesture()) |
|
} |
|
|
|
private func makeGesture() -> some Gesture { |
|
DragGesture(minimumDistance: 0) |
|
.onChanged { _ in |
|
guard timer == nil else { return } |
|
timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in action() } |
|
action() |
|
} |
|
.onEnded { _ in |
|
timer?.invalidate() |
|
timer = nil |
|
} |
|
} |
|
} |
|
|
|
struct ContentView: View { |
|
@ObservedObject var model: Model |
|
|
|
var body: some View { |
|
VStack { |
|
VStack(spacing: 8) { |
|
Text("Value") |
|
Text(String(format: "%.2f", model.value)) |
|
.font(.title) |
|
} |
|
.padding() |
|
|
|
VStack { |
|
Text("Move slider to modify the model value.") |
|
Slider(value: $model.value, in: 0...10) |
|
} |
|
.padding() |
|
.border(Color.white) |
|
|
|
VStack { |
|
Text("Press buttons to step change the model value.") |
|
HStack { |
|
RepeatButton("Down", systemImage: "chevron.left", action: decrementAction) |
|
RepeatButton("Up", systemImage: "chevron.right", action: incrementAction) |
|
} |
|
.labelStyle(IconOnlyLabelStyle()) |
|
} |
|
.padding() |
|
.border(Color.white) |
|
} |
|
} |
|
|
|
private func decrementAction() { changeValue(by: -1.0) } |
|
private func incrementAction() { changeValue(by: 1.0) } |
|
private func changeValue(by: Double) { model.value = min(max(model.value + by, 0), 10) } |
|
} |
|
|
|
let view = ContentView(model: Model()) |
|
PlaygroundPage.current.setLiveView(view) |