На Лекции 8 курса Стэнфорда CS193p — «Developing Application for iOS» («Разработка приложений для iOS») вначале на слайдах, а затем в демонстрационном примере, рассматривается одна короткая тема: легковесное постоянное хранилище (persistent store) UserDefaults, и одна большая главная тема — жесты Gestures, как источник ввода информации пользователем с помощью его пальцев. Далее следует большой демонстрационный пример, в котором обеспечивается превращение Модели EmojiArt документа в JSON и хранения его в UserDefaults. Но главные усилия в этом демонстрационном примере направлены на реализацию жеста pinch, с помощью которого можно масштабировать EmojiArt документа, и жеста pan, с помощью которого можно перемещать EmojiArt документ по экрану. Это НЕ-дискретные жесты, и в SwiftUI есть специальная технология, основанная на использовании @GestureState переменных и пары модификаторов жестов .updating и .onEnded, которую профессор и демонстрирует. По ходу демонстрации профессор также показывает ряд других крутых вещей наподобие анимированных шрифтов.
Использование UserDefaults для запоминания EmojiArt документа — это скорее вынужденный шаг на данном этапе демонстрации, так как пока мы ещё не изучили работу ни с файловой системой iOS, ни с объектно-ориентированной базой данных Core Data, а формировать EmojiArt документ каждый раз заново при запуске приложения в процессе демонстрации — это слишком обременительная работа.
А под руками такое простейшее средство «постоянного хранения» как UserDefaults, которое правда имеет очень древний API, он используется уже довольно давно, ещё до появления SwiftUI или даже Swift, он покажется очень странным для многих из вас на этом курсе, использующих сейчас реально функциональное программирование. Кроме того, UserDefaults довольно ограничен в ТИПах данных, которые он может хранить. Это должен быть Property List.
Но если взглянуть на этот API под определенным углом, то его можно достаточно хорошо вписать в Swift и функциональное программирование. Кроме того, в Swift есть действительно мощный способ преобразования произвольной структуры struct в Property List — это использование протокола Codable.
Сочетание UserDefaults с протоколом Codable обеспечивает «постоянное хранение» EmojiArt документа для демонстрационных целей. Все это присутствует в демонстрационном примере.
Но главная тема Лекции 8 — это жесты. Рассматриваются как дискретные жесты типа «двойного» Tap, так и НЕ-дискретные жесты pinch и pan, их особенности и тонкости реализации.
Та часть демонстрационного примера, которая относится к жестам, начинается с создания дискретного «двойного Tap» жеста, призванного «подогнать» размер EmojiArt документа ко всему доступному пространству. На примере этого в общем-то простого жеста по сравнению с НЕ-дискретными жестами профессор рассматривает все стадии «внедрения» «распознавания» жеста в ваш View через модификатор .gesture с функцией внутри, которая возвращает some Gesture, через создания жеста Gesture, с модификатором .onEnded, воздействующим на @State переменную, изменения которой вызывают обновление View.
Но это просто «разминка» перед созданием НЕ-дискретного жеста pinch (в SwiftUI — MagnificationGesture), который позволяет увеличивать (zoom in) и уменьшать (zoom out) масштаб EmojiArt документа. Здесь уже при создании жеста MagnificationGesture() работают оба модификатора жеста: .onEnded и .updating, и участвуют уже 3 переменных: @State переменная, @GestureState переменная и вычисляемая переменная, которая является комбинацией первых двух переменных и именно она определяет, как обновляется View. Модификатор .onEnded устанавливает @State переменную при окончании жеста, а .updating модификатор обновляет @GestureState переменную на основании оперативной информации о положении пальцев на экране во время выполнения жеста, которая для жеста MagnificationGesture() — очень простая, это число CGFloat соответствующее текущему масштабу.
Абсолютно точно такая же схема работает и для жеста pan (в SwiftUI — DragGesture()), за исключением того, что оперативной информации о положении пальца на экране во время выполнения жеста более сложная — это структура struct и у нее есть location, то есть где в данный момент находится палец, также есть startLocation, то есть откуда начинался жест. Даже есть время time. Это время time обновляется каждый раз, когда происходит обновление, так что вы можете узнать, как быстро движется палец.
Если честно, то я нигде не видела более четкого использования НЕ-дискретных жестов. В Лекции 8 представлен универсальный код для жестов pinch и pan, который можно использовать и в вашем приложении.
Код демонстрационного примера для Лекции 8 находится на сайте курса CS193P и на Github для iOS 13 в папке Memorize L8.
Русскоязычный неавторизованный конспект Лекции 8, хронометрированный через каждые 5 минут, и представленный в виде PDF-файла, который можно скачать и использовать offline, а также в формате Google Doc доступны на платной основе.