Site icon AppTractor

От класса размера к доступному пространству: остается ли horizontalSizeClass надежным параметром?

Как показали на WWDC 26, при зеркальном отображении приложения для iPhone на Mac через функцию iPhone Mirroring, размер его окна можно свободно изменять. Одновременно с этим, приложения для iPhone, работающие на iPad, также получат возможность изменять размер окна. Даже без обновления физического устройства до бета-версии новой ОС, разработчики уже могут оценить это изменение в предварительных версиях Xcode 27 или в среде симулятора iOS 27 в Device Hub.

Однако влияние этого обновления выходит далеко за рамки простого изменения размера окон приложений для iPhone. Оно меняет представление многих разработчиков о системе компоновки. Некоторые характеристики, которые ранее часто использовались в качестве параметров компоновки, такие как horizontalSizeClass, больше не подходят в качестве основного критерия определения ширины окна.

Так является ли это изменение внезапным сдвигом или неизбежным результатом долгосрочной эволюции системы компоновки Apple? В этой статье мы рассмотрим этот вопрос.

Моё приложение для iPhone стало выглядеть некрасиво

Недавно я занимался рефакторингом своего старого проекта, переписывая всё приложение с использованием новых идей программирования и API.

Увидев поведение приложения для iPhone с изменяемым размером, показанное на WWDC 26, я сразу же протестировал, как моё собственное приложение ведёт себя в этом сценарии. Поскольку в приложении уже была зарезервирована логика адаптации для iPhone, iPad и macOS, я изначально предположил, что после растягивания ширины окна в Device Hub существующей адаптивной компоновки будет достаточно для обработки изменений.

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

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

Однако, когда приложение запускается на iPad с использованием идиомы pad, horizontalSizeClass всё ещё изменяется в определённом диапазоне по мере изменения размера окна. Если удалить семейство устройств iPad и запустить приложение на iPad в режиме совместимости только с iPhone, его поведение станет намного ближе к поведению хоста iPhone в Device Hub.

Сначала я подозревал, что это нерешенная проблема в бета-версии 1. Только посмотрев сессию WWDC 26 «Модернизация вашего UIKit приложения», я понял, что это на самом деле было преднамеренным дизайнерским решением Apple.

Это не ошибка бета-версии: новый контракт с WWDC26

В сессии 278 «Модернизация вашего UIKit приложения» Apple явно переносит приложения для iPhone в среду динамического изменения размера:

Это объясняет неинтуитивное поведение, с которым я столкнулся ранее: даже после увеличения ширины окна horizontalSizeClass в хосте iPhone может оставаться compact.

Это не ошибка бета-версии. Это результат того, что Apple намеренно разделяет «семантику хоста» и «доступное геометрическое пространство».

Остаётся ли horizontalSizeClass надёжным?

Короткий ответ: да.

Однако он надёжно отражает лишь обобщённые характеристики текущего окружения трейтов, а не фактическую ширину окна.

Это, пожалуй, одна из самых распространённых ошибок в этом году. Более широкое окно на iPhone не означает, что система обязательно переключит horizontalSizeClass на regular. И наоборот, даже относительно узкое окно iPad может давать совершенно разные результаты в зависимости от его идиомы, сцены, представления или среды контейнера.

Для разработчиков действительно важное изменение заключается не в том, что «iPhone стал iPad», а в следующем:

Поэтому horizontalSizeClass по-прежнему подходит для выражения семантики системного контейнера, например, следует ли сворачивать меню или доступны ли системные вкладки или боковые панели. Но для собственных контрольных точек компоновки приложения, таких как «переключиться на двухколоночную компоновку после определенной ширины» или «показать боковую навигацию», решение должно основываться на фактическом доступном размере текущего корневого представления, контейнерного представления или сцены.

От устройства к сцене, от ориентации к доступному пространству

Если мы посмотрим только на WWDC 26, это изменение легко можно понять как новую проблему, возникшую с появлением функции изменения размера на iPhone.

Но если мы соединим точки за последние несколько лет, мы увидим, что Apple на самом деле все это время двигалась в одном направлении: постоянно уменьшая важность «типа устройства + ориентации экрана» как основы для решений по компоновке и постепенно направляя разработчиков к сценам, иерархии характеристик и доступному пространству.

Полноэкранный режим iPad демонстрирует ту же тенденцию

Изменения в полноэкранном режиме на iPad фактически указывают на ту же тенденцию.

Apple не лишила пользователя права выбирать полноэкранный режим работы, но постепенно возвращает разработчику возможность блокировать приложение в старом режиме совместимости с помощью UIRequiresFullScreen.

В iPadOS 26 пользователи по-прежнему могут выбирать между полноэкранными приложениями, оконными приложениями и Stage Manager через Настройки или Центр управления. Но для разработчиков UIRequiresFullScreen уже определен как устаревший режим совместимости и будет игнорироваться системой в будущем.

Другими словами, полноэкранный режим постепенно превращается из «того, что разработчики могут потребовать» в «то, что определяется совместно пользователем и системой». Подробнее об этом см. в документации Apple TN3192 и UIRequiresFullScreen.

Это возвращает полноэкранный режим iPad и изменение размера iPhone к одному и тому же основному принципу: разработчики могут задавать предпочтения, минимальные размеры и временные блокировки ориентации, но им больше не следует предполагать, что они владеют фиксированным и неизменным холстом.

Возвращаясь к проекту: разработка собственной стратегии компоновки с использованием геометрии

После понимания этих правил я начал пересматривать, как мое приложение должно реагировать на изменение размера экрана iPhone.

Хотя можно инжектировать \.horizontalSizeClass = .regular в поддерево SwiftUI на основе геометрии сцены, позволяя некоторым контейнерам использовать семантику регулярных элементов, это не подходит в качестве глобальной стратегии.

Такой подход влияет на все представления в этом поддереве, которые считывают значение из окружения. При этом разные компоненты по-разному ведут себя при сочетании «тип устройства — iPhone» и «принудительно заданный обычный класс размера».

Например, NavigationSplitView может расширять свою боковую панель, но в моих тестах TabView(.sidebarAdaptable) не становится автоматически боковой панелью в стиле iPad.

Это не означает, что API для включения боковой панели вкладок, представленный UIKit в iOS 27, не имеет ценности. Скорее, это показывает, что «широкое окно iPhone» и «среда навигации iPad» — это не одно и то же.

Другими словами: широкоэкранный iPhone — это всё ещё адаптивное отображение интерфейса iPhone, а не полноценный интерфейс iPad.

Учитывая сценарии моего приложения, я обнаружил, что идея Apple 2024 года о том, что «панель вкладок и боковая панель — это разные представления одной и той же иерархии навигации», очень хорошо подходит для проекта.

Поэтому я определил следующую стратегию для приложения:

Эра фиксированного холста закончилась

В будущем разработчики смогут задавать скорее предпочтения, чем полностью контролировать интерфейс.

Например:

Теперь пользователи сами решают, как будет отображаться приложение, в то время как разработчикам необходимо заранее учитывать больше возможных форм представления. Хотя все больше и больше системных компонентов теперь обладают мощными адаптивными возможностями, и SwiftUI значительно снизил барьер для создания адаптивных интерфейсов, количество сценариев, которые должны обрабатывать разработчики, фактически увеличилось.

Эпоха фиксированного холста подходит к концу, а эра построения интерфейсов с учетом доступного пространства только начинается.

Источник

Exit mobile version