Сделали на сценах. Для iPhone root-сцена называется MobileCalWindow.
Экран дня
Контейнер UINavigationController. Навигацию между страницами-днями сделали на UIScrollView, класс назвали BlockableScrollView. У скрола включен пейджинг.
В памяти хранят вчерашений, сегодняшний и завтрашний день. В Календаре используют кастомную систему переиспользования, что-то похожее на UICollectionView, но управляется вручную. Скорее всего, это сделано для оптимизации в прошлом - считайте легаси-код.
Ячейки событий сделали двухслойными картинками. Первый слой - фоновая картинка, второй слой - текст внутри события. Залитая линия слева у вьюхи события - это часть фоновой картинки. У события две точки для изменения времени - слева внизу и справа вверху. Им сделали большие размеры, но фон - прозрачный. Лейаут ячеек на констрейнтах.
UINavigationBar базовый, справа добавили Stack View для кнопок. Панель с датами назвали PaletteView. Это UIScrollView и она не является частью UINavigationBar. Всю панель поместили над контентом, но под баром и присоединили к нижней точке бара. Фон повторили, чтобы скрыть переход.
![Хедер экрана событий](https://cdn.sparrowcode.io/view-hierarchy/calendar/event-list-header.png)
Разметка времени слева сделана на одном слое, текст отрисовали внутри CALayer. Время разместили слева экрана, события сместились вправо.
![Как устроена разметка времени](https://cdn.sparrowcode.io/view-hierarchy/calendar/time-grid.png)
Разметка времени лежит внутри UIVisualEffectView, но визуальных применений блюра не нашёл.
Как писал выше, событие - это картинка. Чтобы обрабатывать нажатие на картинку, нужно добавить UITapGestureRecognizer. Так инженеры эпл и сделали - для вью каждого дня добавили тап-жест. А вот жест драга добавлен один на весь экран, а не отдельные жесты для каждого события.
Новое событие
Экран презентуется как модальный контроллер. Сделан на UITableViewController, вью таблицы назвали EKCalendarItemEditorTableView.
![Экран с новым событием](https://cdn.sparrowcode.io/view-hierarchy/calendar/new-event.png)
Ячейки назвали EKUITableViewCell. Disclosure Indicator справа - системные. Ничего особенного в этом экране не нашёл.
Экран по месяцам
Главная вью UIScrollView. При переходе на экран по месяцам, панель с числами PaletteView съезжает вверх. Она остается в памяти, но не видна на экране.
А вот панель с днями недели визуально остается на месте, но на самом деле это копия. Оригинальная панель уезжает наверх вместе с PaletteView.
![Экран по месяцам](https://cdn.sparrowcode.io/view-hierarchy/calendar/by-month.png)
Названия месяцев сделаны на UILabel. Месяц разбивается на горизонтальные недели. Контейнер назвали CompactMonthWeekView.
![Недели в экране по месяцам](https://cdn.sparrowcode.io/view-hierarchy/calendar/by-month-week.png)
Внутри дни недели сделаны через CALayer. Только для текущего дня, который красный кружок, дата это UILabel с красным фоном. Назвали CompactMonthWeekTodayCircle. Лейаут на фреймах.
Сепаратор между неделями это UIView с фоном и высотой 0.333.
Превью дня
Всплывающая панель это таблица. Ячейки назвали EKUIOccurrenceTableViewCell. Лейаут на констрейнтах. Практически все расстояния между элементами выставили фиксированным значением. Отступ от краев ячейки тоже.
![Превью дня для экрана по месяцам](https://cdn.sparrowcode.io/view-hierarchy/calendar/by-month-bottom-sheet.png)
Контент ячеек сделан на UILabel. Цветная полоска слева это UIView с фоном.
Экран Год
Надписи годов сделали через UILabel. Контейнер для хедера назвали CompactYearViewYearHeader. Месяцы группируются по 3 в линию. Даты внутри месяца и название отрисовали слоем внутри вью, назвали CompactYearMonthView.
![Экран Год](https://cdn.sparrowcode.io/view-hierarchy/calendar/year-overview.png)
Сделано на UIScrollView с кастомной системой переиспользования.
Список календарей
Сделали таблицей. Ячейки называются EKCalendarChooserCell. Круглые чекмарки слева сделали картинками. Нативный экран без кастомизации.
![Список календарей](https://cdn.sparrowcode.io/view-hierarchy/calendar/calendars.png)
Accessibility
Все интерактивные элементы поддерживают Voice Over и Voice Control. Расставлены подсказки.
![Разметка Accessibility для дня](https://cdn.sparrowcode.io/view-hierarchy/calendar/accessibility-day-events.png)
Управление голосом размечено на каждый час в течение дня. Для событий диктуется заголовок, время, календарь и как взаимодействовать с элементом.
На экране года Voice Control только для месяцев. Voice Over для года и названия месяцев.
![Разметка Accessibility для превью года](https://cdn.sparrowcode.io/view-hierarchy/calendar/accessibility-year-overview.png)
Accessibility добавлен по всему приложению.