Site icon AppTractor

Создаем виджеты для экрана блокировки на SwiftUI

Одной из самых востребованных функций для iOS были настраиваемые экраны блокировки. И, наконец, они появились у нас с последней версией iOS 16. Мы можем заполнить наш экран блокировки красивыми виджетами. Реализовать виджет для экрана блокировки несложно, поскольку его API использует тот же код, что и виджеты домашнего экрана. В этой статье мы узнаем, как реализовать виджеты экрана блокировки для наших приложений.

Давайте начнем с кода, который, возможно, уже есть в вашем приложении для отображения виджетов на главном экране.

struct WidgetView: View {
    let entry: Entry
    
    @Environment(\.widgetFamily) private var family
    
    var body: some View {
        switch family {
        case .systemSmall:
            SmallWidgetView(entry: entry)
        case .systemMedium:
            MediumWidgetView(entry: entry)
        case .systemLarge, .systemExtraLarge:
            LargeWidgetView(entry: entry)
        default:
            EmptyView()
        }
    }
}

В приведенном выше примере у нас есть типичное представление, определяющее виджет. Мы используем среду, чтобы понять семейство виджетов и отобразить представление правильного размера. Все, что нам нужно сделать для поддержки виджетов экрана блокировки, — это удалить оператор по умолчанию и реализовать все новые случаи, определяющие виджеты экрана блокировки.

struct WidgetView: View {
    let entry: Entry
    
    @Environment(\.widgetFamily) private var family
    
    var body: some View {
        switch family {
        case .systemSmall:
            SmallWidgetView(entry: entry)
        case .systemMedium:
            MediumWidgetView(entry: entry)
        case .systemLarge, .systemExtraLarge:
            LargeWidgetView(entry: entry)
        case .accessoryCircular:
            Gauge(value: entry.goal) {
                Text(verbatim: entry.label)
            }
            .gaugeStyle(.accessoryCircularCapacity)
        case .accessoryInline:
            Text(verbatim: entry.label)
        case .accessoryRectangular:
            VStack(alignment: .leading) {
                Text(verbatim: entry.label)
                Text(entry.date, format: .dateTime)
            }
        default:
            EmptyView()
        }
    }
}

Напомню, что система использует разные режимы рендеринга для виджетов экрана блокировки и домашнего экрана. Система предоставляет нам три разных режима рендеринга.

  1. Полноцветный режим для виджетов главного экрана и расширений watchOS с поддержкой цветов. И да, вы также можете использовать WidgetKit для реализации расширений watchOS, начиная с watchOS 9.
  2. В ярком режиме система обесцвечивает текст, изображения и датчики, превращая их в монохромные, и окрашивает их подходяще для фона экрана блокировки.
  3. Акцентный режим используется только в watchOS, где система делит виджет на две группы: по умолчанию и акцентированные. Система окрашивает акцентированную часть вашего виджета в оттенок, который пользователь выбирает в настройках циферблата.

Режим рендеринга доступен через среду SwiftUI, поэтому вы всегда можете проверить, какой режим рендеринга активен, и отразить его в своем дизайне. Например, вы можете использовать разные изображения с разными режимами рендеринга.

struct WidgetView: View {
    let entry: Entry
    
    @Environment(\.widgetRenderingMode) private var renderingMode
    
    var body: some View {
        switch renderingMode {
        case .accented:
            AccentedWidgetView(entry: entry)
        case .fullColor:
            FullColorWidgetView(entry: entry)
        case .vibrant:
            VibrantWidgetView(entry: entry)
        default:
            EmptyView()
        }
    }
}

Как вы можете видеть в приведенном выше примере, мы используем значение среды widgetRenderingMode, чтобы получить фактический режим рендеринга и изменить виджет. Как я уже говорил, в акцентированном режиме система делит ваш виджет на части и раскрашивает их особым образом. Вы можете пометить часть вашей иерархии представлений с помощью модификатора представления widgetAccentable. В этом случае система будет знать, какие представления будут использовать цвет оттенка.

struct AccentedWidgetView: View {
    let entry: Entry
    var body: some View {
        HStack {
            Image(systemName: "moon")
                .widgetAccentable()
            Text(verbatim: entry.label)
        }
    }
}

Наконец, нам нужно настроить наш виджет для поддерживаемых типов.

@main
struct MyAppWidget: Widget {
    let kind: String = "Widget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WidgetView(entry: entry)
        }
        .configurationDisplayName("My app widget")
        .supportedFamilies(
            [
                .systemSmall,
                .systemMedium,
                .systemLarge,
                .systemExtraLarge,
                .accessoryInline,
                .accessoryCircular,
                .accessoryRectangular
            ]
        )
    }
}

Если вы все еще поддерживаете iOS 15, вы можете проверить поддержку новых виджетов экраном блокировки.

@main
struct MyAppWidget: Widget {
    let kind: String = "Widget"
    
    private var supportedFamilies: [WidgetFamily] {
        if #available(iOSApplicationExtension 16.0, *) {
            return [
                .systemSmall,
                .systemMedium,
                .systemLarge,
                .accessoryCircular,
                .accessoryRectangular,
                .accessoryInline
            ]
        } else {
            return [
                .systemSmall,
                .systemMedium,
                .systemLarge
            ]
        }
    }
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WidgetView(entry: entry)
        }
        .configurationDisplayName("My app widget")
        .supportedFamilies(supportedFamilies)
    }
}

Сегодня мы узнали, как внедрить новые виджеты экрана блокировки в iOS 16. Помните, что мы можем повторно использовать один и тот же API для создания дополнений для watchOS. И вы можете легко в коде виджета получить значения среды, чтобы понять, какой режим рендеринга активен в данный момент.

Еще

Exit mobile version