На Лекции 5 курса Стэнфорда CS193p — «Developing Application for iOS» («Разработка приложений для iOS») рассматриваются три чрезвычайно важных темы:
- @ViewBuilder — Что в действительности является аргументом для ZStack, ForEach, GeometryReader и т.д.?
- Shape — я хочу создать своё собственное View.
- ViewModifier — Что в действительности делают функции типа foregroundColor, font, padding и т.д.?
Лекция 5 начинается с небольшого демонстрационного «разогрева»- демонстрируется управления доступом (access control) в игре Memorize.
@ViewBuilder
После демонстрации рассматривается очень важная концепция @ViewBuilder, о которой несколько раз упоминалось в предыдущих Лекциях. В этой Лекции пришло время четко понять, что @ViewBuilder основан на общей технологии, которая была добавлена в Swift
недавно для поддержания список-ориентированного синтаксиса. Как только у нас появляется этот механизм, мы очень быстро обнаруживаем, что существует множество мест, где мы бы хотели иметь список Views, например, мы хотим, чтобы “лицевые” стороны наших карт Card представлялись двумя прямоугольниками с закругленными углами и эмоджи.
@ViewBuilder — это ключевое слово, но оно не является частью языка программирования. @ViewBuilder наподобие @Published или @ObservedObject — это вещь, которая основана на этих новых технологиях.
Вы можете пометить ключевым словом @ViewBuilder любую функцию, возвращающую some View, и компилятор будет интерпретировать всё, что находится внутри фигурных скобок { } этой функции как список Views.
@ViewBuilder возвращает some View, и это единственное View. Именно поэтому он и называется “ViewBuilder”, потому что он “встраивает” этот список Views в единственное View. Это единственное View, в котором многократно комбинируются различные Views может быть TupleView (кортеж Views), либо _ConditionalContent View, это то, что @ViewBuilder создает, когда там находятся if-else синтаксические конструкции, либо EmptyView, что тоже разрешено.
Примечание. В iOS 14 или в SwiftUI2.0 добавлены синтаксические конструкции для if let и оператор switch.
Вы могли бы использовать @ViewBuilder для маркировки параметров функций, которые сами являются функциями, возвращающими some View<.
Shape
Shape — это протокол protocol. Он наследует от View, так что все Shapes являются Views.Так что вы всегда можете разместить Shape в ZStack или где-то ещё и, как мы видели, “бросить” прямоугольник с закругленными углами RoundedRectangle в ZStack — без проблем.
Все Views должны реализовать переменную var body, но протокол Shape и расширение extension этого протокола реализуют её вместо вас. Однако взамен Shape требуется от вас реализации новой функции func path (in rect: CGRect), возвращающей Path. У Path есть целый ряд функций для рисования: линий, дуг, кривых Безье. Все эти вещи позволят вам рисовать так, как будто вы рисуете ручкой. Как только вы реализуете функцию func path (in rect: CGRect), так сразу же Shape обеспечивает вас возможностью быть обведенной .stroke( ) и раскрашенной .fill ( ).
Лучший способ показать, как это работает, это использовать демонстрационный пример, и профессор создает пользовательскую геометрическую фигуру Pie, которая располагается прямо позади эмоджи типа “Привидения”.
Анимация
Анимация View выполняется не так, как анимация Shape, Shapes анимируют самостоятельно напрямую. Views анимируют через своих модификаторов и для того, чтобы понять, как анимируют Views, мы должны сделать паузу в анимации и поговорить о том, что представляют собой модификаторы ViewModifier.
ViewModifier
Мы использовали модификаторы ViewModifiers повсюду в нашей игре Memorize: aspectRatio, padding, font, foregroundColor. Все они — ViewModifiers. Они модифицируют View и возвращают новое View, которое является модифицированной версией View, для которого вызывался модификатор.
Вот, собственно, что делают модификаторы ViewModifiers.
Большинство модификаторов, не все, но большая часть, возможно, реализованы путем вызова очень важной функции протокола View с именем modifier через расширение extension View.
Далее профессор очень подробно рассказывает о механизме функционирования ViewModifiers, о создании пользовательских модификаторов ViewModifiers, и демонстрирует особенности их применения.
Хорошо, что мы прошли весь материал, посвященный модификаторам ViewModifier, потому что на следующей Лекции 6 мы будем говорить об анимации, а когда приходится анимировать Views, а не Shapes, то она осуществляется с помощью модификаторов ViewModifiers.
Код демонстрационного примера для Лекции 5 находится на Github для iOS 13 в папке Memorize L5.
Русскоязычный неавторизованный конспект Лекции 5, хронометрированный через каждые 5 минут, и представленный в виде PDF-файла, который можно скачать и использовать offline, а также в формате Google Doc доступны на платной основе.