В iOS 16 Apple провела масштабную модернизацию Экран Блокировки. Одной из самых ожидаемых функций, которая появилась вместе с обновлением, - виджеты Экрана Блокировки. Как следует из названия, виджеты Экрана Блокировки — это виджеты, отображающие легко просматриваемый контент, который постоянно виден на экране блокировки iPhone и iPad.
Поскольку и виджеты Главного Экрана, и виджеты Экрана Блокировки работают на WidgetKit, способ создания виджета Экран Блокировки очень похож на то, как мы создаем виджеты Главного Экрана. Поэтому в этой статье я не буду показывать вам, как настроить и создать виджет с нуля, как это было описано в моей предыдущей статье.
Вместо этого я сосредоточусь на том, как обновить код существующих виджетов Главного Экрана для поддержки виджетов Экрана Блокировки.
С учетом всего сказанного, давайте начнем!
Краткое Резюме
В демонстрационных целях давайте обновим View Size Widget, который я создал в предыдущей статье. Вкратце напомню, что View Size Widget — это статический виджет Главного Экрана, который отображает размер вью самого виджета. Вот как это выглядит:

Вот полная реализация View Size Widget:
import WidgetKit
import SwiftUI
// MARK: - The Timeline Entry
struct ViewSizeEntry: TimelineEntry {
let date: Date
let providerInfo: String
}
// MARK: - The Widget View
struct ViewSizeWidgetView : View {
let entry: ViewSizeEntry
var body: some View {
GeometryReader { geometry in
VStack {
// Show view size
Text("\(Int(geometry.size.width)) x \(Int(geometry.size.height))")
.font(.system(.title2, weight: .bold))
// Show provider info
Text(entry.providerInfo)
.font(.footnote)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.green)
}
}
}
// MARK: - The Timeline Provider
struct ViewSizeTimelineProvider: TimelineProvider {
typealias Entry = ViewSizeEntry
func placeholder(in context: Context) -> Entry {
// This data will be masked
return ViewSizeEntry(date: Date(), providerInfo: "placeholder")
}
func getSnapshot(in context: Context, completion: @escaping (Entry) -> ()) {
let entry = ViewSizeEntry(date: Date(), providerInfo: "snapshot")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let entry = ViewSizeEntry(date: Date(), providerInfo: "timeline")
let timeline = Timeline(entries: [entry], policy: .never)
completion(timeline)
}
}
// MARK: - The Widget Configuration
@main
struct ViewSizeWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: "com.SwiftSenpaiDemo.ViewSizeWidget",
provider: ViewSizeTimelineProvider()
) { entry in
ViewSizeWidgetView(entry: entry)
}
.configurationDisplayName("View Size Widget")
.description("This is a demo widget.")
.supportedFamilies([
.systemSmall,
.systemMedium,
.systemLarge,
])
}
}Если приведенный выше код не имеет для вас никакого смысла, прежде чем продолжить, я настоятельно рекомендую вам сначала прочитать мою статью под названием «Начало работы с WidgetKit».
Добавление Виджетов Экрана Блокировки в Ваши Приложения
Добавление Поддерживаемых Семейств Виджетов
В iOS 16 Apple представила 3 новых семейства виджетов, которые представляют 3 разных типа виджетов Экрана Блокировки, а именно: accessoryCircular, accessoryRectangular и accessorInline.

Давайте продолжим и сделаем эти 3 новых семейства виджетов поддерживаемыми. Это все, что нам нужно сделать, чтобы добавить поддержку виджета Экрана Блокировки в наше существующее расширение виджета.
struct ViewSizeWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: "com.SwiftSenpaiDemo.ViewSizeWidget",
provider: ViewSizeTimelineProvider()
) { entry in
ViewSizeWidgetView(entry: entry)
}
.configurationDisplayName("View Size Widget")
.description("This is a demo widget.")
.supportedFamilies([
.systemSmall,
.systemMedium,
.systemLarge,
// Add Support to Lock Screen widgets
.accessoryCircular,
.accessoryRectangular,
.accessoryInline,
])
}
}Однако, если вы попытаетесь показать виджет на экране блокировки, вы заметите, что UI нашего существующего виджета выглядит не очень в этих новых форм-факторах. Более того, для семейства accessorInline невозможно получить даже размер вью.

Чтобы со всем этим разобраться, нам нужно будет создать 3 отдельных вью SwiftUI для каждого из этих семейств виджетов.
Реализация UI Виджетов Экрана Блокировки
Предположим, что желаемые UI виджетов Экрана Блокировки следующие:

Мы можем реализовать каждый из них так:
/// Widget view for `accessoryInline `
struct InlineWidgetView: View {
var body: some View {
Text(" 