Разработчики часто сталкиваются с необходимостью автоматического обновления представлений по расписанию, особенно при работе с данными в реальном времени, такими как текущее время, курсы акций или обновления погоды. В таких случаях обеспечение постоянного обновления представлений становится важным для предоставления пользователям самой актуальной информации.
В этой статье мы рассмотрим, как эффективно использовать TimelineView
для обеспечения плавных и своевременных обновлений в представлениях SwiftUI.
TimelineView
был представлен в iOS 15 и позволяет вам планировать и управлять обновлениями ваших представлений через регулярные промежутки времени. Он предоставляет удобный способ обработки динамического содержимого и данных в реальном времени за счет автоматического обновления представлений на основе предварительно заданного расписания.
TimelineView
действует как контейнер, в который вы можете встроить свой контент.
var body: some View { TimelineView(.everyMinute) { context in // Your Content } }
Типы расписания
SwiftUI предоставляет несколько встроенных типов расписаний:
.everyMinute
— для обновления представления временной шкалы в начале каждой минуты..periodic(from:by:)
— для регулярного обновления представления временной шкалы. Принимает дату начала и интервал, который определяет частоту обновлений.
let interval: TimeInterval = 5 // 5 seconds TimelineView(.periodic(from: .now, by: interval)) { context in // Your Content }
.explicit(_:)
— для обновления представления временной шкалы в определенные моменты времени. Принимает последовательность изDate
объектов.
let dates = [ Date(timeIntervalSinceNow: 5 * 60), // in 5 min Date(timeIntervalSinceNow: 15 * 60), // in 15 min Date(timeIntervalSinceNow: 30 * 60) // in 30 min ] TimelineView(.explicit(dates)) { context in // Your Content }
Если встроенных типов расписаний вам недостаточно, то вы можете определить свои собственные, создав тип, соответствующий протоколу TimelineSchedule
.
Для расписания, содержащего только даты в прошлом, на временной шкале отображается последняя дата в расписании. Для расписания, содержащего только даты в будущем, временная шкала рисует свое содержимое, используя текущую дату, пока не наступит первая запланированная дата.
Контекст
Замыкание, создающее содержимое, получает входные данные типа TimelineView.Context
, которые можно использовать для настройки внешнего вида содержимого.
Объект контекста имеет 2 свойства:
date
— дата запуска обновления.cadence
— скорость, с которой представления временной шкалы могут получать обновления.
Каденс
Cadence
— это перечисление со следующими случаями:
.live
— постоянно обновляет вид..seconds
— обновляет представление примерно раз в секунду..minutes
— обновляет вид примерно раз в минуту.
Вы можете использовать каденцию, чтобы скрыть информацию, которая обновляется быстрее, чем текущая скорость обновления представления. Например, вы можете решить, показывать ли секунды или миллисекунды.
let showMilliseconds = context.cadence == .live let showSeconds = context.cadence <= .seconds
Пример проекта
Теперь мы рассмотрим пример проекта, который демонстрирует, как использовать TimelineView
для отображения времени в нескольких часовых поясах, которые будут обновляться автоматически.
Во-первых, нам нужно подготовить список часовых поясов, которые мы хотим отобразить. В этом примере мы будем использовать несколько часовых поясов, доступных в США.
enum USATimeZone: String, CaseIterable { case EDT, CDT, MDT, PDT, AKDT, HST var timeZone: TimeZone { TimeZone(abbreviation: rawValue)! } }
Затем нам нужно реализовать представление, которое будет использоваться для отображения времени в определенном часовом поясе.
struct TimeRow: View { let timeZone: String let time: String var body: some View { HStack { Text(timeZone) .font(.body) Spacer(minLength: 16) Text(time) .font(.headline) } } }
Наконец, мы добавим представление, которое будет отображать TimelineView
со списком часовых поясов.
struct TimeZonesView: View { let timeZones: [TimeZone] = { USATimeZone.allCases .map(\.timeZone) .sorted { $0.secondsFromGMT() > $1.secondsFromGMT() } }() var body: some View { NavigationStack { TimelineView(.periodic(from: .now, by: 1)) { context in List(timeZones, id: \.identifier) { timeZone in let time = formattedTime(context.date, timeZone: timeZone) TimeRow(timeZone: formattedTimeZone(timeZone), time: time) } } .navigationTitle(Text("Time in the USA")) } } private static let timeFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .none formatter.timeStyle = .short return formatter }() private func formattedTime(_ date: Date, timeZone: TimeZone) -> String { let formatter = Self.timeFormatter formatter.timeZone = timeZone return formatter.string(from: date) } private func formattedTimeZone(_ timeZone: TimeZone) -> String { let name = timeZone.localizedName(for: .generic, locale: .current) let abbreviation = timeZone.abbreviation() guard let name, let abbreviation else { return "" } return "\(name) (\(abbreviation))" } }
Надеюсь, вам понравилась статья. Спасибо за прочтение! 🙂