Это Лекция 15 курса Stanford CS193p, весна 2021 года.
Хотя название Лекции «Интеграции с UIKit
«, задача этой Лекции — более широкая, заставить работать наше документо-ориентированное приложение EmojiArt
на iPhone
. До сих пор функциональные возможности приложения EmojiArt
в большей степени были ориентированы на iPad
. Запуск этого приложения на iPhone
показал, что большая часть кода прекрасно адаптируется самой SwiftUI
, например, popover
на iPad
автоматически преобразуется в полноэкранный sheet
на iPhone
, но не все работает так гладко.
Например, нам пришлось добавить ещё три способа получения фонового изображения background
для нашего документа, ибо перетягивание его из Safari
, находящегося тут же на экране iPad
, в случае iPhone
не работает.
Вот эти способы :
- копирование и вставка (Copy & Paste) изображения c Pasteboard
- изображение с фотокамеры
- изображение из Библиотеки Фотографий (
Photo Library
)
Для этого мы должны были решить вопрос размещения множества кнопок Button
, соответствующих различным способам получения фонового изображения документа, на панели инструментов toolbar
, а также вопросы интеграции UIKit
API фотокамеры и Библиотеки Фотографий (Photo Library
) в SwiftUI
приложение.
Адаптивная панель инструментов compactableToolbar.
В виду того, что на iPhone
в портретном режиме не удается разместить множество кнопок Button
из-за нехватки места, была придумана и реализована компактная панель инструментов compactableToolbar
. Она представляет собой обычную панель инструментов toolbar
, которая размещает множество кнопок Button
, представленных @ViewBuilder
, на панели инструментов toolbar
, за исключением случая, когда не хватает места, в этом случае все кнопки размещаются в контекстном меню для одной единственной кнопки.
Факт нехватки достаточного места определяется с помощью концепции Size Class
, которая существует на iOS
устройствах как по горизонтали, так и по вертикали. Size Class
— это просто перечисление enum
, в котором два значения: compact
и regular
. Использовании концепции Size Class
в SwiftUI
коде намного упрощает написание кода и делает это единообразно во всех приложениях по сравнению с попыткой посмотреть на фактическое количество пикселей, когда вы можете прийти к не совсем правильным решениям при определенных обстоятельствах.
Компактная панель инструментов compactableToolbar
реализована в виде классического ViewModifier
с @ViewBuilder
замыканием в качестве аргумента.
Как работает UIKit.
UIKit
— это старый способ разработки приложений для iOS
. Когда появился SwiftUI
, то он в значительной степени делал всё, что делает UIKit
, но есть кое-что, что мы все же хотели бы интегрировать в SwiftUI
из UIKit
, в первую очередь, это касается фотокамеры, которую мы будем интегрировать в наше приложение EmojiArt
. Кроме того, есть код, написанный множеством разработчиков, который также желательно интегрировать в SwiftUI
. К счастью, это довольно просто сделать, и мы увидим, как именно это делается.
В UIKit
нет MVVM
, вместо этого там то, что называется MVC
(Model View Controller). В MVC
архитектуре Views
как бы сгруппированы вместе и управляются тем, что называется Controller.
В SwiftUI
у нас нет никаких Controllers, там Views
— это просто Views
, и мы представляем их на экране, когда хотим. Но в UIKit
Views
размещаются на экране совершенно по-другому. По сути, мы представляем на экране Controller, а уже Controller управляет своими Views
. Из-за того, что у нас есть Controller интеграция между SwiftUI
и UIKit
требует 2-х точек интеграции.
Эти две точки интеграции очень похожи, одна из них — UIViewRepresentable
, это SwiftUI
View
, которое представляет UIKit
View
, а другая точка — UIViewControllerRepresentable
, также SwiftUI
View
, но представляющее UIKit
Controller и все Views
, которыми этот Controller управляет.
Кроме того, UIKit
является объектно-ориентированным. Это не функциональное программирование. Это совершенно другой Мир, он не декларативный, он не реактивный, ничего из этого в этом Мире нет. Он интенсивно использует концепцию, называемую делегированием (delegation). Поэтому, выполняя интеграцию между SwiftUI
и UIKit
, мы должны обеспечить делегатом delegate
наши UIKit
View
или Controller, чтобы они могли полноценно функционировать, потому что в большинстве случаев им нужен этот делегат delegate
, чтобы делать что-то по существу.
Надо сказать, что Apple
создала на удивление простой API
для такой интеграции SwiftUI
и UIKit
и Пол Хэгерти подробно рассматривает его для интеграции UIKit
API фотокамеры и UIKit
API Библиотеки Фотографий (Photo Library
) в SwiftUI
приложение EmojiArt
. В нем предлагается добавить еще один способ получения фонового изображения непосредственно с фотокамеры (.camera
) или из библиотеки фотографий (.photoLibrary
). Для фотокамеры используется UIImagePickerController
, а для библиотеки фотографий новый PHPicker
, который появился только в iOS 14.
В обоих случаях для интеграции используется UIViewControllerRepresentable
. Оба UIKit
API имеют делегата delegate
, так что вы наглядно сможете увидеть, как они интегрируется в SwiftUI
. В роли делегата delegate
выступает координатор Coordinator
, который извлекает информацию из методов делегата delegate
с помощью замыкания.
Код демонстрационного примера для Лекции 15 находится на Github для iOS 14 в папке EmojiArtL 15.
Русскоязычный неавторизованный конспект Лекции 15, иллюстрированный, хронометрированный и представленный в виде PDF-файла, который можно скачать и использовать offline, а также в формате Google Doc доступны на платной основе.