Подготовьтесь к новому выпуску iOS 16 и watchOS 9 с помощью этого руководства по виджетам на экране блокировки.

Введение

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

Итак, давайте посмотрим, как мы можем расширить наши приложения с помощью новых блестящих виджетов.

Виджеты экрана блокировки

Хорошо, о чем все это на самом деле? Усложнения от watchOS пришли к iOS в виде новых виджетов экрана блокировки. Это также означает, что если мы соблюдаем набор правил стиля, мы можем один раз написать код для наших виджетов и использовать его на разных устройствах. Фреймворк, используемый для создания виджетов в SwiftUI, называется WidgetKit. Возможно, вы знакомы с ним, он существует с 2020 года и выпуска iOS 14. Но теперь исходное семейство виджетов (как его называет Apple) было расширено с новыми нюансами.

В исходное семейство виджетов добавлено 3 новых типа виджетов:

  • accessoryRectangular, который показывает многострочный текст или даже меньшие графики
  • accessoryCircular, используется для отображения прогресса и датчиков
  • accessoryInline, который представляет только текст и полезен для более длинного контента.

accessoryCorner тоже существует, но поскольку он используется исключительно в watchOS, мы сохраним его для другого раза.

Они могут быть представлены в 3 различных стилях окраски. Но на iOS, чтобы соответствовать привлекательности экрана блокировки, можно использовать только ненасыщенную версию на наших виджетах экрана блокировки. Мы можем проверить внешний вид и видимость наших виджетов в Xcode Live View или создать их непосредственно в симуляторе. Поскольку виджеты существуют в отдельной схеме, легко сэкономить время и перестроить их только во время работы с ними, но мы поговорим об этом в разделе учебника позже.

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

Будьте краткими

Место, которое мы получаем для наших виджетов, весьма ограничено. Мы всегда должны быть краткими и показывать только важную информацию. Думайте об этом как о хорошем. Вам не нужно показывать много, например, название приложения или любой текст в этом отношении. Возьмем, к примеру, фитнес-виджет Apple. Он показывает только 3 концентрических круга прогресса без текста или цифр, но пользователи точно знают, какой круг показывает какие данные.

Кроме того, может быть полезно заключить содержимое виджета в ViewThatFits{ ... }, особенно если вы избегаете автоматического многоточия в более длинном тексте.

Не забывайте о дизайне

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

Чтобы применить эти стили, мы используем такие модификаторы, как:

Проверьте свои виджеты с красочным фоном, который может сделать содержимое менее заметным. Мы можем воспользоваться AccessortWidgetBackground()here, который дает нам красивый непрозрачный фон.

Подключите свои виджеты и приложения

Виджеты экрана блокировки действуют очень похоже на расширения watchOS, поэтому с ними нельзя взаимодействовать. Они предназначены для отображения просматриваемого контента из вашего приложения, а не элементов, на которые можно нажать. При касании они входят в приложение на открытом в данный момент экране или, если реализовано, делают прямую ссылку на определенное представление внутри приложения. Я не буду вдаваться в подробности о глубоких ссылках, потому что это совсем другая статья в блоге, но как только вы настроите ее для своего приложения, вы можете просто добавить .widgetURL(entry.url) в вид вашего виджета, и он будет работать как шарм.

Конфиденциальность

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

Как мы можем реализовать редактирование конфиденциальных данных, когда экран заблокирован, спросите вы? Допустим, мы показываем некоторые конфиденциальные данные в прямоугольном виджете. Мы можем представить заполнитель, когда экран заблокирован, и наоборот:

Это применимо и к другим форматам виджетов. Чтобы добиться этого в SwiftUI, просто добавьте модификатор .privacySensitive() в представление. Вы можете пометить только конфиденциальные данные, такие как текст, и, например, оставить отображаемые значки. Это замаскированное представление также можно использовать в качестве скелетного представления во время загрузки данных.

Оставайтесь с нами, чтобы увидеть, как добиться этого в коде ⌨️.

Учебник 📚

Настройка 🔧

Добавьте новую цель в свой проект и найдите Widget Extension.

Дайте цели виджетов имя. Например, мое приложение называется Sparkle, поэтому моя цель будет называться SparkleWidgets.

Теперь откройте файл SparkleWidgets.swift. Здесь можно найти весь код, связанный с виджетами.

Чтобы кратко объяснить автоматически сгенерированный код в файле, мы можем увидеть:

  • Поставщик временной шкалы, который отвечает за время обновления виджета.
  • Представление ввода, используемое для визуализации пользовательского интерфейса для виджетов, похожее на представления SwiftUI, с которыми вы, вероятно, уже знакомы.
  • Конфигурация виджета, которая связывает конфигурацию поставщика с представлением и устанавливает некоторые конфигурации для виджета, например типы поддерживаемых виджетов, отображаемые имена и т. д.
  • Preview Provider, инструмент Xcode для предварительного просмотра в реальном времени.

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

Выполнение

Существует 3 типа виджетов экрана блокировки, и мы хотим решить, как будет отображаться каждый из наших виджетов, а также какие данные он будет отображать. Самый распространенный способ добиться этого — использовать оператор switch case в теле представления следующим образом:

Для этого вам понадобится widgetFamily значение среды. Вы, наверное, заметили представление Gauge, новое для виджетов iOS. Он имеет множество стилей на выбор и обычно показывает диапазон или прогресс для чего-то из нашего приложения.

Передача данных между приложениями

В идеале мы хотели бы отображать какие-то динамические данные в нашем виджете без особого использования статического текста.

Итак, давайте добавим в смесь еще одну специю: давайте поделимся данными из нашего основного приложения с самим виджетом. Это можно сделать несколькими способами, но рекомендуется использовать группы приложений и параметры пользователя по умолчанию.

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

Вот как:

Выберите основную цель и перейдите на вкладку Signing & Capabilities. Затем нажмите кнопку + Capability в верхнем левом углу и найдите параметр App Groups. Это должно появиться в вашем окне Xcode:

Добавьте новый контейнер с помощью кнопки «плюс». Вы должны назвать его, используя этот формат: group.your_app's_bundle_id. Вы можете найти свой идентификатор пакета, быстро переключившись на вкладку General. Установите флажок в разделе «Группы приложений» на вкладке Signing & Capabilities, и настройка завершена.

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

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

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

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

Отказ от ответственности: если вы используете пользовательские типы для передачи данных, они не будут видны в схеме виджета. Чтобы сделать класс видимым, откройте файл класса/структуры в Xcode и откройте правую боковую панель. Затем перейдите на первую вкладку под названием Identity and Type и обязательно установите флажок рядом с целью виджета в разделе Target Membership. Допустим, я решил использовать свой собственный Todotype вместо строки. Тогда мой файл Todo.swift будет иметь следующее членство:

После применения украшений мой код виджета accessoryRectangular теперь выглядит примерно так:

И виджет выглядит примерно так:

Давайте также реализуем круговой виджет. Я буду использовать ранее упомянутое представление Gauge, чтобы показать соотношение «выполнено ко всем задачам». Мы должны разделить готовую задачу на общее количество задач. Поскольку наш датчик используется в качестве круга прогресса, этот результат будет значением датчика. А для текстовой части мы покажем это в виде дроби. Код будет выглядеть так:

Если бы вы хотели, скажем, линейный индикатор выполнения, вы бы использовали accessoryLinearCapacity.

Обновление виджета 🔄

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

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

Вот тут и приходит на помощь класс WidgetCenter из WidgetKit, точнее, функция WidgetCenter.shared.reloadAllTimelines(). Выполнение этой строки сделает именно то, что говорит имя. Кроме того, вы можете указать, какую временную шкалу перезагрузить, используя reloadTimelines(ofKind: String).

Давайте запустим эту штуку на устройстве и посмотрим, что у нас получилось:

И вуаля 🪄.

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

Куда пойти отсюда?

Есть несколько вещей, которые нужно попробовать дальше. Например, вы можете попробовать создать наши недавно созданные виджеты в качестве усложнений для Apple Watch. Или реализовать третий тип виджета, accessoryInline.

Я также рекомендую вам проверить новый экран блокировки Живые действия. Они объединяют WidgetKit, который мы только что использовали, с инфраструктурой ActivityKit и могут быть логически объединены с нашими виджетами экрана блокировки.

Спасибо за прочтение. Веселиться!

Want to Connect?
This story was originally published here. Also, I'd be happy to connect on GitHub and LinkedIn.