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()
    }
}

结果: