Новое в UIKit с iOS 15

UISheetPresentationController

В iOS 15 появились sheet-контроллеры. Их можно перетаскивать с изменением высоты. Вы встречали эти контроллеры в приложениях «Карты» и «Акции».

UISheetPresentationController
Имя Автора
Автор Воробей Иван iOS разработчик. Пишу библиотеки, веду телеграм-канал.

Попытки управлять высотой модальных контроллеров мучают разработчиков уже 4 года. Библиотеки получаются паршивыми: работают отвратительно или вообще не работают. За попытку обсудить эту тему на планёрке выкинули из окна ведущего инженера UIKit. К iOS 15 Тим Кук сжалился и открыл секретное знание.



Выглядит круто, кейсов использования много. Чтобы показать дефолтный sheet-controller, используйте код:

let controller = UIViewController()
if let sheetController = controller.sheetPresentationController {
    sheetController.detents = [.medium(), .large()]
}
present(controller, animated: true)

Это модальный контроллер, которому добавили сложное поведение. Можно оборачивать в навигационный контроллер, добавлять заголовок и бар-кнопки. Оберните код с sheetController в if #available(iOS 15.0, *) {}, если проект поддерживает предыдущие версии iOS.

Detents (стопоры)

Стопор - это высота, к которой стремится контроллер. Прямо как в пейджинге скролла или когда электрон не на своём энергетическом уровне.

Доступно два стопора: .medium() с размером примерно на половину экрана и .large(), который повторяет большой модальный контроллер. Если оставить только .medium()-стопор, то контроллер откроется на половину экрана и подниматься выше не будет. Установить свою высоту нельзя.

Переключение между стопорами

Чтобы перейти из одного стопора в другой, используйте код:

sheetController.animateChanges {
    sheetController.selectedDetentIdentifier = .medium
}

Можно вызывать без блока анимации.

Альбомная ориентация

По умолчанию sheet-контроллер в альбомной ориентации выглядит как обычный контроллер. Дело в том, что .medium() -стопор недоступен, а .large() - это и есть дефолтный режим модального контроллера. Но можно добавить отступы по краям.

sheetController.prefersEdgeAttachedInCompactHeight = true

Вот как это выглядит:

Landscape for UISheetPresentationController

Чтобы контроллер учитывал prefered-размер, установите .widthFollowsPreferredContentSizeWhenEdgeAttached в true.

Индикатор

Чтобы добавить индикатор вверху контроллера, установите .prefersGrabberVisible в true. По умолчанию индикатор спрятан. Индикатор не влияет на safe area и layout margins, по крайней мере, на момент написания статьи.

Grabber for UISheetPresentationController

Затемнение фона

Указываете самый большой стопор, который не нужно затемнять. Всё, что больше этого стопора, будет затемняться. Код:

sheetController.largestUndimmedDetentIdentifier = .medium

Указано, что .medium затемняться не будет, а всё, что больше, будет. Можно убрать затемнение для самого большого стопора.

Corner Radius

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

Grabber for UISheetPresentationController

На скриншоте я установил corner-радиус в 22. Радиус сохраняется для .medium-стопора. На этом всё. Напишите в коментариях к посту, будете ли использовать в своих проектах sheet-контроллеры.