Как устроено приложение Календарь в iPhone

Добро пожаловать в разбор кейсов, как Apple использует элементы UIKit в своих приложениях. Сегодня разберу Календарь. Я - Иван Воробей, веду телеграмм канал для iOS Разработчиков «Код Воробья».

Календарь сделали на сценах. Для iPhone root-сцена называется MobileCalWindow.

Экран дня

Контейнер UINavigationController. Навигацию между страницами-днями сделали на UIScrollView, класс назвали BlockableScrollView. У скрола включен пейджинг.

В памяти хранят вчерашений, сегодняшний и завтрашний день. В Календаре используют кастомную систему переиспользования, что-то похожее на UICollectionView, но управляется вручную. Скорее всего, это сделано для оптимизации в прошлом и до нашего времени сохранился легаси-код.

Ячейки событий сделали двухслойными картинками. Первый слой - фоновая картинка, второй слой - текст внутри события. Залитая линия справа события это часть фоновой картинки. У события две точки для изменения времени - слева внизу и справа вверху. Им расширили размеры, но фон - прозрачный. Лейаут ячеек на констрейнтах.

UINavigationBar базовый, справа добавили Stack View для кнопок. Панель с датами назвали PaletteView. Это UIScrollView и она не является частью UINavigationBar. Всю панель поместили над контентом, но под баром и присоединили к нижней точке бара. Фон повторили, чтобы скрыть переход.

Разметка времени слева сделана на одном слое, текст отрисовали внутри CALayer. Время разместили слева экрана, события сместились вправо.

Разметка времени лежит внутри UIVisualEffectView, но визуально применений не нашёл.

Как писал выше, событие - это картинка. Чтобы обрабатывать нажатие на картинку, нужно добавить UITapGestureRecognizer. Так инженеры эпл и сделали - для вью каждого дня добавили тап-жест. В вот жест драга добавлен один на весь экран, а не отдельные жесты для каждого события.

Новое событие

Экран презентуется как модальный контроллер. Сделан на UITableViewController, вью таблицы назвали EKCalendarItemEditorTableView.

Ячейки назвали EKUITableViewCell. Disclosure Indicator справа тоже системные. Ничего уникального в экране не нашёл.

Экран по месяцам

Главная вью UIScrollView. При переходе на экран по месяцам, панель с числами PaletteView съезжает вверх. Она остается в памяти, но не видна на экране телефона.

А вот панель с днями недели визуально остается на месте, но на самом деле это копия. Оригинальная панель уезжает наверх вместе с PaletteView.

Названия месяцев сделаны на UILabel. Месяц разбивается на горизонтальные недели. Контейнер назвали CompactMonthWeekView.

Внутри дни недели сделаны через CALayer. Только для текущего дня, который красный кружок, дата это UILabel с красным фоном. Назвали CompactMonthWeekTodayCircle. Лейаут на фреймах.

Сепаратор между неделями это UIView с фоном и высотой 0.333.

Превью дня

Всплывающая панель это таблица. Ячейки назвали EKUIOccurrenceTableViewCell. Лейаут на констрейнтах. Практически все расстояния между элементами выставили фиксированным значением. Отступ от краев ячейки тоже.

Контент ячеек сделан на UILabel. Цветная полоска слева это UIView с фоном.

Экран Год

Надписи годов сделали через UILabel. Контейнер для хедера назвали CompactYearViewYearHeader. Месяцы группируются по 3 в линию. Даты внутри месяца и название отрисовали слоем внутри вью, назвали CompactYearMonthView.

Сделано на UIScrollView с кастомной системой переиспользования.

Список календарей

Сделали таблицей. Ячейки называются EKCalendarChooserCell. Круглые чекмарки слева сделали картинками. Нативный экран без кастомизации.

Accessibility

Все интерактивные элементы поддерживают Voice Over и Voice Control. Расставлены подсказки.

Управление голосом размечено на каждый час в течение дня. Для событий диктуется заголовок, время, календарь и как можно взаимодействовать с элементом.

На экране года Voice Control только для месяцев. Voice Over для года и названия месяцев.

Accessibility добавлен по всему приложению.