Листаем цифровые страницы: UIPageViewController
UIPageViewController — это компонент пользовательского интерфейса iOS, который предлагает удобный способ навигации между последовательными страницами контента. Он использует постраничную модель представления, позволяющую пользователям пролистывать страницы влево или вправо с помощью жестов.
Этот контроллер особенно полезен в приложениях, где контент должен быть представлен в формате, напоминающем физические страницы. Например, в приложениях для чтения книг, образовательных курсах, галереях изображений или даже в некоторых типах интерактивных руководств. UIPageViewController обеспечивает дополнительный уровень привлекательности и удобства использования приложения.
Сегодня я хочу поделиться кратким и простым руководством о том, как просто и программно реализовать UIPageViewController. Итак, что же мы получим в итоге?
Для начала определим класс ContentViewController, который реализует собственный контроллер представления. Этот класс предназначен для использования в UIPageViewController, где каждая страница представлена экземпляром ContentViewController. Это позволяет легко создавать несколько страниц с различными цветами текста и фона:
class ContentViewController: UIViewController {
private lazy var textLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 25, weight: .bold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupConstraints()
}
private func setupViews() {
view.addSubview(textLabel)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
textLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8)
])
}
func configure(with text: String, backgroundColor: UIColor) {
textLabel.text = text
view.backgroundColor = backgroundColor
}
}
configure (with: backgroundColor:):
Этот метод позволяет настроить textLabel
и цвет фона контроллера снаружи. Параметр text
используется для установки текста в textLabel
, а backgroundColor
— для установки цвета фона view
Теперь создадим класс PageViewController, который наследуется от UIPageViewController. Этот класс эффективно управляет созданием и отображением различных страниц, каждая из которых представлена экземпляром ContentViewController с настраиваемым цветом текста и фона:
class PageViewController: UIPageViewController {
var pages: [ContentViewController] = []
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
let pageData: [(String, UIColor)] = [
("Let's", .paleLavender),
("Get", .paleTurquoise),
("Started", .paleGreen)
]
for (text, color) in pageData {
let contentVC = ContentViewController()
contentVC.configure(with: text, backgroundColor: color)
pages.append(contentVC)
}
if let firstPage = pages.first {
setViewControllers([firstPage], direction: .forward, animated: true, completion: nil)
}
}
}
Что мы здесь делаем:
Создаем массив пустых страниц pages, который будет содержать экземпляры ContentViewController
Создаем массив кортежей pageData [(String, UIColor)], где каждый кортеж содержит строку и цвет. Эти данные используются для настройки каждой страницы в UIPageViewController
Проходим циклом по каждому элементу pageData (где каждый элемент — это кортеж) и для каждого элемента создаем новый экземпляр ContentViewController, далее вызывает метод configure для настройки contentVC и добавляем сконфигурированный contentVC в массив pages
Далее проверяем, находится ли первая страница в массиве страниц. Если страница существует, она устанавливается в качестве текущего активного контроллера в UIPageViewController
Устанавливает сам PageViewController в качестве источника данных (dataSource) для UIPageViewController. Это необходимо для управления содержимым страниц.
Все, что нам осталось сделать, это реализовать протокол UIPageViewControllerDataSource, который используется для предоставления контроллеров представления, которые будут отображаться в UIPageViewController:
extension PageViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let contentVC = viewController as? ContentViewController,
let currentIndex = pages.firstIndex(of: contentVC),
currentIndex > 0 else {
return nil
}
return pages[currentIndex - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let contentVC = viewController as? ContentViewController,
let currentIndex = pages.firstIndex(of: contentVC),
currentIndex < pages.count - 1 else {
return nil
}
return pages[currentIndex + 1]
}
}
Эти два метода обеспечивают логику отображения контроллера и плавную и последовательную навигацию между страницами.
Рассмотрим каждый метод подробно:
pageViewController (_: viewControllerBefore:):
Этот метод определяет, какой контроллер должен быть показан перед текущим контроллером в
UIPageViewController
guard let
проверяет, что текущий контроллер является экземпляромContentViewController
и определяет его текущий индекс в массивеpages
currentIndex > 0
гарантирует, что текущий контроллер не является первым в массиве, что позволяет избежать выхода за пределы массиваЕсли условие выполняется, метод возвращает контроллер представления, который находится перед текущим (
pages[currentIndex - 1]
). Если условие не выполняется, метод возвращаетnil
, указывая, что предыдущего контроллера нет
pageViewController (_: viewControllerAfter:):
Этот метод определяет, какой контроллер должен отображаться после текущего контроллера в
UIPageViewController
Аналогично первому методу,
guard let
проверяет, что текущий контроллер является экземпляромContentViewController
и определяет его индексcurrentIndex < pages.count - 1
проверяет, что текущий контроллер не является последним в массивеЕсли условие выполняется, метод возвращает следующий контроллер представления (
pages[currentIndex + 1]
). Если нет, то возвращаетnil
, указывая на отсутствие следующего контроллера
Добавляем в App или Scene:
let pageViewController = PageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil)
window?.rootViewController = pageViewController
PageViewController предлагает различные стили перехода и ориентации навигации:
Параметры TransitionStyle: параметр .pageCurl имитирует эффект перелистывания настоящей книги или журнала, .scroll предоставляет опцию, при которой страницы скользят горизонтально или вертикально.
NavigationOrientation определяет, будет ли пользователь перемещаться по страницам горизонтально или вертикально.