После обновления iOS элементы UIKit прижались к краям, хотя constraints проекта не менялись.

В Xcode 27.2 RC сначала проверьте, полагался ли дочерний UIView на отступы по умолчанию: в iOS 27.1 и новее стандартные layout margins обычного UIView равны нулю. Если содержимому нужен отступ, задайте directionalLayoutMargins явно либо настройте наследование от родителя, а затем повторите проверку на целевой версии системы. Это не означает, что все контролы автоматически становятся краевыми: у корневого представления контроллера остаётся отдельный источник системных минимальных отступов. Такое различие подтверждено в примечаниях Apple к iOS 27.2 RC.

Материал пригодится вам, если вы поддерживаете UIKit Auto Layout и заметили изменение расстояний после обновления iOS.
Он также подойдёт команде, которая проверяет совместимость приложения с iOS 27.1 или новее и хочет отличить отступы корневого представления от отступов дочерних UIView.
Если вы запускаете Xcode и симулятор на удалённом Mac, здесь найдёте порядок воспроизводимой регрессии — без предположений о конкретной конфигурации узла.

Последняя проверка — 25 октября 2026 года. Поведение и рекомендации сверены с документацией Apple по UIKit и требованиями Xcode к macOS. Если Apple обновит описание поведения или выпустит новую версию, повторно проверьте документацию и выполните тест на целевой системе.

01

Xcode 27.2 RC: смещение отступов UIKit начинается с проверки источника

Ключевая перемена не в том, что UIKit удалил все отступы во всём интерфейсе. В iOS 27.1 и более новых версиях layout margins обычного UIView по умолчанию равны нулю. Системное поведение корневого представления контроллера описывается отдельно: UIViewController предоставляет ему минимальные системные отступы, значение которых зависит от контекста отображения.

Поэтому сначала установите, какое именно представление задаёт направляющую, к которой привязано содержимое. Визуально одинаковое смещение может иметь разные причины:

  • constraint привязан к layoutMarginsGuide дочернего представления, а его margins теперь нулевые;
  • содержимое привязано к направляющей корневого представления контроллера, где действуют системные минимальные значения;
  • дочерний view не сохраняет отступы родителя;
  • код проекта меняет margins после создания constraints;
  • safe area ошибочно принимают за layout margins.

Сам факт, что интерфейс выглядит плотнее, ещё не доказывает изменение safe area или ошибку Auto Layout. Сопоставьте версию системы, иерархию представлений и конкретный экран. В описании layout margins от Apple объясняется роль направляющих для размещения содержимого; это помогает не смешивать их с безопасной областью.

Почему в iOS 27.1 стандартные отступы UIView стали нулевыми?

Причина для диагностики здесь не в произвольном изменении constraints, а в подтверждённом поведении UIKit: стандартные layout margins обычного UIView в iOS 27.1 и более новых версиях равны нулю. Системные минимальные отступы корневого представления контроллера при этом описываются отдельно.

Практическое следствие зависит от того, как собран экран. Если UILabel, контейнер карточки или собственный компонент привязан к собственному layoutMarginsGuide, а его margins нигде не настроены, контент может приблизиться к краю. Если constraint использует направляющую корневого представления контроллера, поведение может быть иным. Если элемент привязан напрямую к safe area или anchors родительского view, причина может лежать в другом месте.

Не назначайте виновником любое изменение интерфейса, замеченное после установки нового runtime. Проверьте одну и ту же сборку и один сценарий на двух целевых версиях системы. Зафиксируйте конкретное представление, визуальный результат и используемый layout guide. Такое сравнение отделяет изменение стандартных margins от перестроения экрана, ошибки привязки или независимого изменения safe area.

02

Сначала отделите корневые margins от margins дочернего view

Начните с дерева представлений, а не с массовой правки storyboard или кода. Для проблемного элемента проследите цепочку от него до корневого view controller и ответьте на три вопроса:

  • К какому anchor привязан элемент: к краю родителя, layoutMarginsGuide или safeAreaLayoutGuide?
  • У какого именно объекта запрашиваются margins?
  • Не назначаются ли они повторно после создания view или при изменении состояния экрана?

Корневое представление контроллера имеет отдельные systemMinimumLayoutMargins. Их значение связано с контекстом, в котором отображается контроллер; не переносите наблюдение с одного контейнера на все экраны. В документации Apple о минимальных margins корневого view описан именно этот уровень иерархии.

Отдельно проверьте, какое свойство указано в constraints. Привязка к view.layoutMarginsGuide корневого view controller и привязка к contentView.layoutMarginsGuide используют разные объекты. Если у второго объекта margins равны нулю, системное значение корневого представления не обязано автоматически появиться у него.

В Xcode откройте экран на целевом runtime и исследуйте view hierarchy. Выберите проблемный view, просмотрите его constraints и фактические значения margins. Затем проверьте, какое значение получает родитель и не переопределено ли оно в viewDidLoad, viewWillLayoutSubviews, обработчике размера контейнера или при конфигурации ячейки. Если визуальная проблема воспроизводится только на одном экране, не меняйте глобально все компоненты: найдите первое звено, где ожидаемое значение отступа перестаёт совпадать с фактическим.

Для минимального воспроизведения оставьте только контроллер, родительский контейнер, один дочерний view и один constraint к его layoutMarginsGuide. Сравните результат на целевой версии системы и на версии, где экран выглядел правильно. Если минимальный пример показывает тот же сдвиг, это подтверждает зависимость от стандартных margins. Если нет, возвращайте элементы по одному, пока не обнаружится отличие в иерархии или конфигурации.

03

Наследование от родителя требует явного решения

preservesSuperviewLayoutMargins не означает «всегда копировать отступы родителя». Это свойство помогает дочернему представлению сохранять margins родителя в ситуациях, когда собственная настройка дочернего view иначе вывела бы содержимое за родительские отступы. Apple описывает именно сохранение границ родительских margins, а не универсальное исправление любого смещения. Проверьте документацию свойства preservesSuperviewLayoutMargins применительно к конкретной цепочке view.

Если компонент должен следовать внутренним отступам контейнера, включите наследование у нужного дочернего представления и проверьте результат в иерархии. Не включайте флаг без разбора у всех view: это может изменить компоновку там, где компонент намеренно использует собственную систему отступов. Для самостоятельной карточки, ячейки или вложенного контейнера явная конфигурация часто понятнее — особенно если её границы являются частью дизайна.

При выборе учитывайте назначение компонента:

  • Дочерний view должен соблюдать поля контейнера. Проверьте preservesSuperviewLayoutMargins и убедитесь, что constraints используют ожидаемую направляющую.
  • У компонента есть собственный дизайн-токен отступов. Настройте directionalLayoutMargins явно, не полагаясь на значение по умолчанию.
  • Родитель и ребёнок имеют разные правила. Сохраните отдельные margins и привяжите каждый constraint к намеренно выбранному guide.
  • Источник значения неясен. Сначала проследите фактическую иерархию и места присваивания; не добавляйте наследование как пробную глобальную заплатку.

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

04

Как воспроизвести проблему в Xcode 27.2 RC

Чтобы выяснить, действительно ли дефект вызван стандартными margins, соберите минимальный сценарий. Цель — повторить ту же иерархию, что и на проблемном экране, но исключить посторонние компоненты, навигацию и другие переменные.

  • Выберите экран, на котором изменение видно лучше всего. Запишите, какой дочерний view выглядит смещённым и к какому guide он должен быть привязан.
  • Откройте проект в Xcode 27.2 RC и убедитесь, что используемая версия macOS соответствует опубликованным требованиям Xcode. Не предполагайте, что нужный runtime доступен при любой установленной версии инструментария.
  • Запустите приложение в симуляторе с целевой версией iOS. Сохраните версию runtime, параметры сборки и последовательность действий, при которой появляется дефект.
  • В отладчике компоновки проверьте margins корневого view, родителя и проблемного дочернего view. Сопоставьте значения с направляющими, на которые ссылаются constraints.
  • Измените только один фактор: настройте margins явно или включите наследование для выбранного view. Соберите проект повторно и сравните результат на том же экране.
  • Повторите проверку на версии системы, где исходная компоновка была ожидаемой, и на целевой версии. Не меняйте одновременно constraints, margins и safe area: иначе вы не поймёте, какое изменение устранило проблему.

В логе Auto Layout ищите конфликтующие constraints и предупреждения о невозможной компоновке, но не считайте отсутствие таких сообщений доказательством корректных margins. Constraints могут быть непротиворечивыми, хотя привязаны не к тому guide. Сначала проверьте объект, у которого запрошен layoutMarginsGuide, затем проследите цепочку до родителя.

Если проблема проявляется в таблице или коллекции, проверяйте конфигурацию конкретной ячейки и её contentView отдельно. Переиспользование ячеек может скрыть присваивание margins, сделанное не в том месте или только при одном состоянии. В простом экране без переиспользования дефект может не повториться — это не опровергает проблему исходной иерархии.

05

Явные margins, safe area и направленность — три разные проверки

Если исправление через явное значение не помогло, проверьте, на какую именно направляющую ссылается constraint. Установка directionalLayoutMargins меняет directional margins представления, но не перепривязывает существующие constraints автоматически. Если constraint всё ещё относится к другому view или его краям, изменение свойства не обязано сдвинуть содержимое.

Также проверьте порядок исполнения. Значение могли установить при создании view, а затем заменить при конфигурации экрана, обновлении состояния или повторном использовании компонента. Найдите все присваивания directionalLayoutMargins, layoutMargins и preservesSuperviewLayoutMargins. Проверьте, не применяется ли значение к родителю вместо дочернего view или наоборот.

Не подменяйте margins безопасной областью. safeAreaLayoutGuide отвечает за безопасное размещение относительно системных областей, а layoutMarginsGuide — за внутренние отступы содержимого. Их взаимодействие можно менять отдельными настройками; Apple объясняет его в документации insetsLayoutMarginsFromSafeArea. Сначала выясните, что использует экран: безопасную область, layout margins или обе направляющие в разных constraints.

Как проверить RTL после настройки directionalLayoutMargins

directionalLayoutMargins задаёт отступы по направлениям leading и trailing, а не по физическим сторонам left и right. Благодаря этому интерфейс может учитывать направление письма. При проверке включите локаль с направлением справа налево и убедитесь, что симметричный или асимметричный дизайн ведёт себя как задумано. Соответствие направлений описано в документации Apple по directionalLayoutMargins.

Если продукт поддерживает RTL, проверьте не только визуальную позицию контейнера, но и constraints внутренних элементов. Не переводите directional margins в жёсткие left и right только ради устранения одного дефекта. Иначе компоновка может выглядеть исправленной в одном языке, но неверной в другом.

У SwiftUI-контейнера и встроенного UIKit-представления могут быть разные источники отступов. Проверьте границу между ними: кто задаёт размер размещения, к чему привязаны UIKit constraints и где применяется SwiftUI padding. Добавление padding снаружи может замаскировать проблему, но не доказывает, что UIKit view получает правильные margins. Сведите пример к одному контейнеру и одному встроенному view, затем меняйте по одному источнику компоновки.

06

Алгоритм выбора исправления: отметьте подтверждённые условия

Используйте этот список после проверки view hierarchy. Отмечайте только те пункты, которые подтверждены фактическими значениями и используемыми constraints; действие в соответствующей строке и будет выбранным исправлением.

  • [ ] Constraint проблемного элемента использует layoutMarginsGuide дочернего view, а его margins равны нулю. Если компоненту нужны собственные постоянные поля, задайте directionalLayoutMargins явно и проверьте направленность в RTL.
  • [ ] Дочерний view должен следовать внутренним полям родителя, и у родителя margins заданы правильно. Настройте preservesSuperviewLayoutMargins только у этого дочернего view; затем убедитесь, что constraints используют нужную направляющую.
  • [ ] Смещение обнаружено на корневом представлении контроллера. Проверьте systemMinimumLayoutMargins и контекст отображения. Не заменяйте системное поведение случайной константой и не переносите корневую настройку на все дочерние представления.
  • [ ] Проблемный constraint не использует margins. Не меняйте directionalLayoutMargins: вернитесь к проверке anchor, safe area и размеров контейнера.
  • [ ] Фактические значения меняются после первоначальной компоновки. Найдите позднее присваивание и исправьте его источник, вместо того чтобы добавлять второе переопределение.

Если подходит несколько пунктов, исправляйте сначала тот источник, который непосредственно используется проблемным constraint. После изменения повторите сценарий на исходной и целевой версиях iOS. Если дефект сохраняется, вернитесь к дереву представлений и проверьте следующую причину, а не накапливайте несколько одновременных обходных решений.

Для явной настройки используйте семантические направления и значения проекта, а не случайные константы в разных экранах:

var margins = contentView.directionalLayoutMargins
margins.leading = horizontalInset
margins.trailing = horizontalInset
contentView.directionalLayoutMargins = margins

Здесь horizontalInset должен ссылаться на уже принятую в проекте величину или на намеренно введённый дизайн-токен. Затем проверьте, что constraints действительно используют contentView.layoutMarginsGuide. Иначе код меняет margins, которые ни один проблемный constraint не читает.

07

Приёмка исправления на целевой системе

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

Перед завершением регрессии сохраните:

  • версию iOS и runtime симулятора;
  • версию Xcode и используемую конфигурацию сборки;
  • исходный экран, последовательность воспроизведения и view, у которого обнаружено отличие;
  • изменение кода: явные directional margins, наследование или исправление constraint;
  • результат на целевой системе, исходной системе и в RTL, если приложение поддерживает это направление;
  • наличие или отсутствие конфликтов Auto Layout и подтверждение, что margins задаются в ожидаемом месте.

Проверяйте не только первый кадр после запуска. Откройте экран обычным путём в приложении, повторите переходы, которые меняют состояние view, и проверьте повторное использование ячеек, если оно есть. Если после этого layout остаётся корректным на целевом runtime, а исходная версия не получила нежелательного сдвига, исправление можно передавать на дальнейшую приёмку. Для устройств, где это возможно, дополните результат отдельной проверкой на физическом оборудовании.

08

Когда удалённый Mac уместен для такой регрессии

Для проверки UIKit-компоновки вам нужен доступ к совместимой среде Xcode, целевому runtime и проекту. Удалённый Mac может быть удобен, если локальный компьютер не подходит для установки нужной версии инструментов или если вы хотите изолировать тестовую среду от основной рабочей машины. Но удалённая работа добавляет зависимость от сети и способа доступа; для визуальной оценки взаимодействия с физическими датчиками симулятор не заменяет устройство.

Если текущая схема — один локальный Mac, её слабые места для повторяемой проверки могут быть конкретными: системное обновление затрагивает и рабочую среду, дисковое пространство делят проект и инструменты, а тестовую конфигурацию сложнее отделить от повседневной. Отдельный Mac, в свою очередь, требует бюджета и обслуживания; аренда не подходит, если вам постоянно нужна одна и та же физическая периферия или непрерывная тяжёлая нагрузка. Для короткого цикла проверки сначала сравните текущий набор инструментов с условиями аренды Mac, а сам формат удалённой среды оцените по информации о VpsMesh.

Практический порядок остаётся неизменным: найдите view, от которого реально читается layout guide, выберите явные directional margins или наследование и подтвердите результат на целевой iOS. Если для этого нужно временно запускать разные сборки Xcode и симуляторы на отдельной машине, удалённый Mac от VpsMesh может избавить от постоянной нагрузки на локальный компьютер. Сначала проверьте совместимость инструментов и требования проекта; если важнее локальная периферия или постоянная работа без сетевой зависимости, собственный Mac будет прямее.