#ios #swift #xcode #swiftui
#iOS #swift #xcode #swiftui
Вопрос:
Я хочу, чтобы в моем приложении был секундомер, который работает полностью вне времени устройства. У меня есть приведенный ниже код, который определяет время нажатия кнопки «Пуск», а затем каждую секунду обновляет secondsElapsed
значение, равное разнице между startTime
текущим и текущим. Я застрял на реализации функции паузы. Если я просто аннулирую таймер обновления, то таймер перезапустится, в значительной степени продолжив работу с того места, где он остановился. Есть идеи о том, как это можно сделать?
class StopWatchManager: ObservableObject{
@Published var secondsElapsed = 0
var startTime: Date = Date()
var timer = Timer()
func startWatch(){
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ timer in
let current = Date()
let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current)
let seconds = (diffComponents.second ?? 0)
self.secondsElapsed = seconds
}
}
func pauseWatch(){
timer.invalidate()
}
}
Я отображаю секундомер, используя этот код ниже:
struct ContentView: View {
@ObservedObject var stopWatchManager = StopWatchManager()
var body: some View{
HStack{
Button("Start"){
stopWatchManager.startWatch()
}
Text("(stopWatchManager.secondsElapsed)")
Button("Pause"){
stopWatchManager.pauseWatch()
}
}
}
}
Ответ №1:
ДА. Вот как это сделать:
- При нажатии кнопки «Пауза» отметьте текущее время и вычислите прошедшее время для таймера. Аннулируйте таймер обновления.
- Когда таймер возобновится, возьмите текущее время и вычтите прошедшее время. Сделайте это
startTime
и перезапустите таймер обновления.
Вот обновленный код:
class StopWatchManager: ObservableObject{
@Published var secondsElapsed = 0
var startTime: Date = Date()
var elapsedTime = 0.0
var paused = false
var running = false
var timer = Timer()
func startWatch(){
guard !running else { return }
if paused {
startTime = Date().addingTimeInterval(-elapsedTime)
} else {
startTime = Date()
}
paused = false
running = true
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true){ timer in
let current = Date()
let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current)
let seconds = (diffComponents.second ?? 0)
self.secondsElapsed = seconds
}
}
func pauseWatch(){
guard !paused else { return }
timer.invalidate()
elapsedTime = Date().timeIntervalSince(startTime)
paused = true
running = false
}
}
Что следует отметить:
- Я изменил интервал таймера на
0.1
from1
, чтобы избежать пропуска обновлений. - Я добавил
paused
running
переменные состояния и, чтобы кнопки не нажимались более одного раза подряд.
Комментарии:
1. При возобновлении работы таймера вы имеете в виду отсчет времени во время нажатия, а затем вычитание прошедшего времени? Я думаю, что меня путают имена моих переменных и ваша формулировка. Спасибо за помощь!
2. Да, потратьте время на нажатие кнопки возобновления и вычтите прошедшее время, чтобы получить новое
startTime
. У меня есть код, который нужно добавить к моему ответу. Прежде чем я добавлю его, какой кнопкой вы хотите отключить таймерStart
илиPause
? Или, возможноPause
, следует изменить наUnpause
илиResume
, когда время приостановлено.3. В моем полном приложении кнопка меняется с «Начать просмотр» на «Приостановить просмотр» (при нажатии), а затем обратно на «Начать просмотр». Поэтому я хотел бы начать снимать его с паузы
4.
let diffComponents = Calendar.current.dateComponents([.second], from: self.startTime, to: current)
?? почему нетDate().timeIntervalSince(startTime)
илиstartTime.timeIntervalSinceNow
также?5.
Date().addingTimeInterval(-elapsedTime)
также может быть записан какDate(timeIntervalSinceNow: -elapsedTime)
или простоDate() - elapsedTime