I'm looking to show Text
when scrolling but hide the text when not scrolling using digitalCrownRotation
(like the indicator shown when scrolling). Currently it's only working one way when I scroll and doesn't work at too well, would this be possible to accomplish?
extension View {
func hidden(_ shouldHide: Bool) -> some View {
opacity(shouldHide ? 0 : 1)
}
}
struct ContentView: View {
@State var date: Date = Date()
@State var scroll: Double = 0.0
@State var previous: Double = 0.0
@State var scrolling: Bool = false
var body: some View {
VStack {
Text("\(date.dateFormat("E, d MMM"))")
.focusable(true)
.hidden(!scrolling)
.digitalCrownRotation($scroll, from: 0, through: 365, by: 1, sensitivity: .low, isContinuous: false, isHapticFeedbackEnabled: true)
.onChange(of: scroll) { value in
scrolling = (value > previous)
previous = value
date = Calendar.current.date(byAdding: .day, value: Int(value), to: Date())!
}
}
.onAppear {
self.date = Date()
}
}
}
You need to show your view while user scrolls and hide when he ended doing so.
I suggest you using .debounce
from Combine. What it does it waits for some time (1 sec in my example, should be fine for you) after each new value passed, and only pass it if no new value was sent during this time.
So in this case it'll wait 1 sec after last crown touch before hiding the view:
@State var date: Date = Date()
@State var scroll: Double = 0.0
@State var scrolling: Bool = false
private let relay = PassthroughSubject<Double, Never>()
private let debouncedPublisher: AnyPublisher<Double, Never>
init() {
debouncedPublisher = relay
.removeDuplicates()
.debounce(for: 1, scheduler: RunLoop.main)
.eraseToAnyPublisher()
}
var body: some View {
VStack {
Text("\(date)")
.focusable(true)
.opacity(scrolling ? 1 : 0)
.digitalCrownRotation($scroll, from: 0, through: 365, by: 1, sensitivity: .low, isContinuous: false, isHapticFeedbackEnabled: true)
.onChange(of: scroll) { value in
withAnimation {
scrolling = true
}
relay.send(value)
date = Calendar.current.date(byAdding: .day, value: Int(value), to: Date())!
}
.onReceive(
debouncedPublisher,
perform: { value in
withAnimation {
scrolling = false
}
}
)
}
.onAppear {
self.date = Date()
}
}
Result: