TimeLineView 如何获得它的 context.cadence?

问题描述 投票:0回答:0

除了 WorkoutManager 类中的一些细微变化外,我几乎完全遵循this Apple Sample Code。但是,在 Always On 模式下的模拟器上进行测试时,Apple 的应用程序将其

context.cadence
.live
切换为
.seconds
,而我的应用程序将其
context.cadence
切换为
.minutes
。因此,我的应用程序没有像 Apple 应用程序那样经常更新。我不知道我在哪里做任何不同的事情或如何将我的设置为
.seconds
- 我认为这是默认设置?

我的代码:

struct LiveWorkoutTabView: View {
    
    @State var tabIndex:Int = 1
    @EnvironmentObject var workoutManager:
    
    var body: some View {
        if workoutManager.workoutIsActive {
            TimelineView(MetricsTimelineSchedule(from: workoutManager.startDate ?? Date(),
                                                 isPaused: workoutManager.session?.state == .paused)) { context in
                TabView(selection: $tabIndex) {
                    WorkoutControlsView(liveWorkoutTabViewIndex: $tabIndex).environmentObject(workoutManager)
                        .tabItem { Group{
                        }}.tag(0)
                    LiveWorkoutHeartView().environmentObject(workoutManager)
                        .tabItem { Group{
                        }}.tag(1)
                }
                .onChange(of: context.cadence, perform: { newValue in
                    print("cadence = \(newValue)")
                })
                .navigationTitle {
                    HStack {
                        ElapsedTimeView(elapsedTime: workoutManager.builder?.elapsedTime(at: context.date) ?? 0, showSubseconds: context.cadence == .live)
                        Spacer()
                    }
                }
                
            }
            
        }
        
    }
}

struct WorkoutTabView_Previews: PreviewProvider {
    static var previews: some View {
        LiveWorkoutTabView().environmentObject(WorkoutManager())
    }
}

//For making the timer only show seconds when Always On display is on, Code from: https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/build_a_workout_app_for_apple_watch
struct ElapsedTimeView: View {
    var elapsedTime: TimeInterval = 0
    var showSubseconds: Bool = true
    @State private var timeFormatter = ElapsedTimeFormatter()
    
    var body: some View {
        Text(NSNumber(value: elapsedTime), formatter: timeFormatter)
            .font(.body)
            .foregroundColor(.white)
            .monospacedDigit()
            .onChange(of: showSubseconds) {
                timeFormatter.showSubseconds = $0
            }
    }
}

class ElapsedTimeFormatter: Formatter {
    let componentsFormatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.minute, .second]
        formatter.zeroFormattingBehavior = .pad
        return formatter
    }()
    var showSubseconds = true
    
    override func string(for value: Any?) -> String? {
        guard let time = value as? TimeInterval else {
            return nil
        }
        
        guard let formattedString = componentsFormatter.string(from: time) else {
            return nil
        }
        
        
        
        if showSubseconds {
            let hundredths = Int((time.truncatingRemainder(dividingBy: 1)) * 100)
            let decimalSeparator = Locale.current.decimalSeparator ?? "."
            return String(format: "%@%@%0.2d", formattedString, decimalSeparator, hundredths)
        }
        
        return formattedString
    }
}

private struct MetricsTimelineSchedule: TimelineSchedule {
    var startDate: Date
    var isPaused: Bool
    
    init(from startDate: Date, isPaused: Bool) {
        self.startDate = startDate
        self.isPaused = isPaused
    }
    
    func entries(from startDate: Date, mode: TimelineScheduleMode) -> AnyIterator<Date> {
        var baseSchedule = PeriodicTimelineSchedule(from: self.startDate,
                                                    by: (mode == .lowFrequency ? 1.0 : 1.0 / 30.0))
            .entries(from: startDate, mode: mode)
        
        return AnyIterator<Date> {
            guard !isPaused else { return nil }
            return baseSchedule.next()
        }
    }
}

苹果代码:

struct MetricsView: View {
    @EnvironmentObject var workoutManager: WorkoutManager
    
    var body: some View {
        TimelineView(MetricsTimelineSchedule(from: workoutManager.builder?.startDate ?? Date(),
                                             isPaused: workoutManager.session?.state == .paused)) { context in
            VStack(alignment: .leading) {
                ElapsedTimeView(elapsedTime: workoutManager.builder?.elapsedTime(at: context.date) ?? 0, showSubseconds: context.cadence == .live)
                    .foregroundStyle(.yellow)
                Text(Measurement(value: workoutManager.activeEnergy, unit: UnitEnergy.kilocalories)
                        .formatted(.measurement(width: .abbreviated, usage: .workout, numberFormatStyle: .number.precision(.fractionLength(0)))))
                Text(workoutManager.heartRate.formatted(.number.precision(.fractionLength(0))) + " bpm")
                Text(Measurement(value: workoutManager.distance, unit: UnitLength.meters).formatted(.measurement(width: .abbreviated, usage: .road)))
            }
            .font(.system(.title, design: .rounded).monospacedDigit().lowercaseSmallCaps())
            .frame(maxWidth: .infinity, alignment: .leading)
            .ignoresSafeArea(edges: .bottom)
            .scenePadding()
            .onChange(of: context.cadence, perform: { newValue in
                print("cadence = \(newValue)")
            })
        }
                                             
    }
}

struct MetricsView_Previews: PreviewProvider {
    static var previews: some View {
        MetricsView().environmentObject(WorkoutManager())
    }
}

private struct MetricsTimelineSchedule: TimelineSchedule {
    var startDate: Date
    var isPaused: Bool

    init(from startDate: Date, isPaused: Bool) {
        self.startDate = startDate
        self.isPaused = isPaused
    }

    func entries(from startDate: Date, mode: TimelineScheduleMode) -> AnyIterator<Date> {
        var baseSchedule = PeriodicTimelineSchedule(from: self.startDate,
                                                    by: (mode == .lowFrequency ? 1.0 : 1.0 / 30.0))
            .entries(from: startDate, mode: mode)
        
        return AnyIterator<Date> {
            guard !isPaused else { return nil }
            return baseSchedule.next()
        }
    }
}
swift swiftui apple-watch watchos timelineview
© www.soinside.com 2019 - 2024. All rights reserved.