AppDelegate отходит на второй план. SceneDelegate вступает во владение.
iPadOS 13 был выпущен во время WWDC 2019. Наконец, у iPad есть отдельная ОС.
Введение поддержки нескольких окон в iPadOS - это революционный шаг. Это позволяет нам одновременно открывать несколько экземпляров приложения.
Эта потрясающая функция невероятно полезна, когда дело доходит до просмотра нескольких сообщений, электронных писем или сравнения заметок и маршрутов на карте. Это также упростит жизнь редакторам фото и видео. Я верю, что поддержка нескольких окон очень скоро приведет к появлению интересных многопользовательских игр!
Наша цель на сегодня
- Знание того, как поддержка многооконного режима меняет жизненный цикл приложения.
UIScene
API с высоты птичьего полета.- Реализовать поддержку нескольких окон двумя разными способами - с пользовательским вводом и с помощью перетаскивания. Мы будем разрабатывать приложение для редактирования фотографий для iOS и iPadOS, которое использует
CIFilters
на изображении человека-паука!
Не теряя больше времени, приступим.
Включение поддержки многооконного режима
Это просто, просто перейдите в навигатор проекта, откройте общие настройки и убедитесь, что установлен флажок поддерживать несколько окон.
Как только это будет сделано, в info.plist
. Прежде чем мы углубимся в изменения и реализацию API, давайте обратимся к слону в комнате.
Поддержка нескольких окон не является поддержкой разделенного экрана
Поддержка разделенного экрана была введена в iOS 9 для просмотра различных приложений в одном окне, тогда как поддержка нескольких окон позволяет одновременно просматривать несколько экземпляров одного приложения.
Изменения в AppDelegate и жизненном цикле приложения
Поддержка многооконного режима внесла серьезные изменения в класс AppDelegate
. Сейчас он намного светлее. Вся тяжелая работа выполняется классом SceneDelegate
. Если вы посмотрите на AppDelegate
в любом проекте iOS 13 Xcode, вы увидите, что у него очень мало методов.
UIApplicationDelegate
не уведомляется, когда приложение запускается и запускается в фоновом режиме в iOS 13 и более поздних версиях.
Недавно представленный протокол UIWindowSceneDelegate
обрабатывает уведомления в нескольких окнах приложения.
Следующие свойства класса UIApplication
объявлены устаревшими:
statusBarStyle
statusBarHidden
statusBarOrientation
open(_:options:completionHandler:)
keyWindows
Благодаря поддержке многооконного режима окна теперь являются сценами! Итак, начиная с iPadOS 13, все, что вы видите в переключателе приложений, представляет собой отдельную сцену.
UIScene API: взгляд с высоты птичьего полета
Поддержка нескольких окон использует UIScene
API под капотом. Двумя наиболее важными классами этого API являются:
UIWindowScene
- отвечает за управление несколькими окнами приложения.UISceneSession
- представляет постоянное состояние сцены. НесколькоUIScene
s хранят там определенную информацию, такую как информация о роли и пользователе с сеансом сцены.
NSUserActivity
используется для захвата состояния сцены. Это состояние используется для восстановления ранее использованной сцены или создания новой сцены с текущим просматриваемым контентом.
UIWindowSceneDelegate
реализуется SceneDelegate
. Этот протокол является новой записью в приложении, поскольку он содержит ссылки на UIWindow
.
UIWindow
теперь содержит ссылку на UIWindowScene
. Если вы используете раскадровку, свойство UIWindow
будет автоматически прикреплено к сцене.
Не используете раскадровки? Вам необходимо вручную прикрепить UIWindow
к сцене в классе SceneDelegate
, как показано ниже:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(frame: windowScene.coordinateSpace.bounds) window?.windowScene = windowScene }
Если вышесказанное не имело особого смысла, практическая реализация в следующем разделе, несомненно, внесет больше ясности. Давайте копаться!
Примечание. Никогда не используйте поддержку нескольких окон для расширения функциональности сцен. Или показывая результат одной сцены в другой. Каждая сцена должна иметь полную функциональность приложения.
Реализация
Мы будем создавать приложение для редактирования фотографий, которое позволит просматривать изображения с разными фильтрами в разных сценах. Это удобно, когда нужно определить, какой фильтр лучше всего смотрится на изображении!
Укладка пользовательского интерфейса
Следующий фрагмент кода программно добавляет на экран UIImageView
:
let VCActivityType = "VCKey" func setupImageView(){ photo = UIImageView(frame: .zero) photo?.translatesAutoresizingMaskIntoConstraints = false view.addSubview(photo!) NSLayoutConstraint.activate([ photo!.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: marginConstant), photo!.bottomAnchor.constraint(equalTo: self.stackView!.topAnchor, constant: -marginConstant), photo!.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: marginConstant), photo!.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -marginConstant), ]) }
Создание новой сцены по щелчку пользователя
Чтобы создать новую сцену приложения, добавьте следующий код при нажатии кнопки:
let activity = NSUserActivity(activityType: VCActivityType) UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil, errorHandler: nil)
requestSceneSessionActivation
отвечает за активацию существующей сцены или создание новой сцены.
Вот скриншот из приложения для iPad.
Это было просто. Теперь давайте перейдем к механизму перетаскивания и посмотрим, что там нужно сделать.
Создание новой сцены с помощью перетаскивания
Мы можем использовать API перетаскивания, передав NSUserActivity
внутри DragItem
NSItemProvider
.
Когда вы перетаскиваете компонент пользовательского интерфейса, система автоматически предоставляет точки перетаскивания (обычно по краям экрана). Падение в этих точках приводит к созданию новой сцены.
Чтобы создать новую сцену с помощью перетаскивания UIImageView
, мы должны позаботиться о трех вещах:
1. Соответствие UIDragInteractionDelegate
Нам нужно настроить взаимодействие перетаскивания на UIImageView
.
photo?.isUserInteractionEnabled = true photo?.addInteraction(UIDragInteraction(delegate: self))
2. Реализация функции перетаскивания.
В приведенном ниже фрагменте мы передаем imageView
NSItemProvider
и регистрируем NSUserActivity
с ним.
extension ViewController : UIDragInteractionDelegate{ func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] { if let imageView = interaction.view as? UIImageView { guard let image = imageView.image else { return [] } let provider = NSItemProvider(object: image) let userActivity = NSUserActivity(activityType: VCActivityType) provider.registerObject(userActivity, visibility: .all) let item = UIDragItem(itemProvider: provider) return [item] } return [] } }
3. Добавление ActivityType в Info.plist
Наше приложение для iPad теперь готово для поддержки многооконного режима с помощью перетаскивания.
Мы установили CIFilters
на изображениях, чтобы сравнивать одно и то же изображение с помощью разных фильтров.
Поддержка многооконности также совместима с Mac Catalyst.
Заключение
Итак, это все! Мы видели, как AppDelegate
отходит на второй план и позволяет SceneDelegate
выполнять основную работу по поднятию тяжестей, обрабатывая большинство событий жизненного цикла.
Наконец, мы реализовали поддержку многооконного режима и увидели наше дружелюбное окружение в разных оттенках в разных сценах.
Полный исходный код этой статьи доступен на GitHub.
В следующих частях мы рассмотрим восстановление состояния и синхронизацию данных в нескольких окнах в iPadOS.
Вот и все. Надеюсь, вам понравилось.