SwiftUI - 在 Digital Crown 旋转期间显示视图
SwiftUI - show view during Digital Crown rotation
我希望在滚动时显示 Text
,但在不滚动时使用 digitalCrownRotation
隐藏文本(就像滚动时显示的指示器一样)。目前,当我滚动时,它只能以一种方式工作,而且效果不佳,这有可能实现吗?
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()
}
}
}
您需要在用户滚动时显示您的视图,并在他结束滚动时隐藏。
我建议您使用 Combine 中的 .debounce
。它的作用是在每个新值传递后等待一段时间(在我的示例中为 1 秒,对您来说应该没问题),并且只有在这段时间内没有发送新值时才传递它。
因此在这种情况下,它会在最后一次按表冠触摸后等待 1 秒,然后再隐藏视图:
@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()
}
}
结果:
我希望在滚动时显示 Text
,但在不滚动时使用 digitalCrownRotation
隐藏文本(就像滚动时显示的指示器一样)。目前,当我滚动时,它只能以一种方式工作,而且效果不佳,这有可能实现吗?
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()
}
}
}
您需要在用户滚动时显示您的视图,并在他结束滚动时隐藏。
我建议您使用 Combine 中的 .debounce
。它的作用是在每个新值传递后等待一段时间(在我的示例中为 1 秒,对您来说应该没问题),并且只有在这段时间内没有发送新值时才传递它。
因此在这种情况下,它会在最后一次按表冠触摸后等待 1 秒,然后再隐藏视图:
@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()
}
}
结果: