iPhone Duo для iOS-разработчика: что реально меняется в вашем Swift-коде

в 5:18, , рубрики: ios 27, iphone duo, Size Classes, swiftUI, uikit, xcode, адаптивная вёрстка, мобильная разработка, складной iphone

9 сентября 2026 года Apple показала iPhone Duo — свой первый складной iPhone. Внешний экран 5.4″, внутренний 7.6″ в раскрытом виде, поставка с iOS 27.1, старт продаж 23 октября. Для пользователя история про железо и «самый тонкий iPhone». Для нас с вами история в другом: часть допущений, зашитых в iPhone-приложения с 2007 года, перестала быть правдой.

Экранов теперь больше одного. Экран может менять форму прямо во время работы приложения. Safe area больше не симметрична. А «только портрет» означает совсем не то, что вы привыкли под этим понимать.

Хорошая новость: если вы уже делали адаптивную вёрстку по-человечески ради iPad, здесь работы на один вечер. Если приложение хардкодит размеры экрана и ветвится по ориентации — придётся засучить рукава.

iPhone Duo в раскрытом виде: внутренний экран 7,6″, внешний 5,4″. Фото: Apple

iPhone Duo в раскрытом виде: внутренний экран 7,6″, внешний 5,4″. Фото: Apple

Небольшая, но важная оговорка про источники и статус

Весь код ниже — из официальных Apple Tech Talks для iPhone Duo (шесть докладов, команды UI Frameworks и дизайна): это сэмплы прямо со страниц Apple, а не мои догадки. Под каждым разделом — ссылка на конкретный доклад, чтобы вы могли проверить сами.

Но два честных нюанса, которые важно держать в голове:

  1. Символы iOS 27.1 пока pre-release. DocC-страниц по ReservedRegion, ArrangementView, onHingeChange, CameraCaptureAccessory и т.п. ещё нет (отдают 404) — их написание известно только по сэмпл-коду и озвучке докладов и может измениться до релиза SDK. Поэтому копипастить в прод вслепую не стоит: сверяйтесь с SDK, когда он выйдет.

  2. Инструментов ещё нет на руках. На середину сентября 2026 бета Xcode 27.1 с симулятором iPhone Duo и полным SDK обещана «позже в этом месяце», но пока не вышла — Device Hub с позами устройства недоступен. Смотреть доклады и планировать рефакторинг можно уже сейчас; прогнать по всем позам — только когда приедет бета.

Что будет, если не делать ничего

Приложение продолжит запускаться. Оно не упадёт и его не снимут с продажи. Но сколько экрана вы получите на внутреннем дисплее — зависит от того, каким SDK вы собирались в последний раз:

  • Старый SDK, без пересборки — работает, но в «letterbox»: старое соотношение сторон и чёрные поля по бокам.

  • iOS 27 SDK — растягивается влево от статус-бара, обходя зону камеры.

  • iOS 27.1 SDK — полноэкранный edge-to-edge, стандартные кнопки навигации и тулбара раскладываются вертикально.

Так что нулевой шаг — банально пересобраться под iOS 27.1 SDK. Одно это переводит вас из состояния «очевидно не обновлялись» в «нормально». Всё остальное ниже — это разница между «нормально» и «хорошо».

Первоисточник: Apple, Tech Talk «Prepare your app for iPhone Duo».

Ментальная модель: четыре позы

Главный сдвиг в голове. Это больше не «портрет против ландшафта». Это:

  1. Закрыто, портрет — ведёт себя как обычный iPhone

  2. Закрыто, ландшафт

  3. Раскрыто, вертикально (высокий, почти квадратный формат)

  4. Раскрыто, горизонтально (широкий формат)

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

Для ориентира в цифрах: внутренний дисплей — это примерно 669×951 поинт при 3x (соотношение ~1.42), внешний — 466×678. То есть внутренний экран для вашего кода вёрстки, по сути, «айпадоформный». (Apple официально поинт-размеры не публиковала: 466×678 берётся из спецификации скриншотов App Store Connect напрямую, а 669×951 — из неё же, 2007×2853 px ÷ 3, как обоснованная оценка; финально подтвердит или поправит Device Hub. Держите как ориентир, а не как константу.)

Показательно, что сам HIG просит меньше «попозовой» вёрстки, чем ждёшь: спроектируйте под два size class и дайте системе самой «расставлять позы». Цель — континуальность (бесшовный переход при открытии и закрытии), а не ручное разруливание каждой позы.

Первоисточник: Apple, Tech Talk «Design for iPhone Duo» и Human Interface Guidelines: Designing for iPhone Duo.

Изменение 1. Size classes, а не ориентация

Это самая важная строка во всех рекомендациях Apple, и именно она сломает больше всего приложений.

Внутренний дисплей не подчиняется вашим supported interface orientations. Если layout ветвится по UIDevice.orientation или по supportedInterfaceOrientations — эта логика теперь врёт вам в лицо.

Смотрите на size classes: они описывают пространство, которое у вас есть, — а это ровно то, что вам на самом деле нужно.

// SwiftUI
struct ContentView: View {
    @Environment(.horizontalSizeClass) private var hSize

    var body: some View {
        if hSize == .regular {
            WideLayout()
        } else {
            CompactLayout()
        }
    }
}
// UIKit
override func traitCollectionDidChange(_ previous: UITraitCollection?) {
    super.traitCollectionDidChange(previous)
    let isWide = traitCollection.horizontalSizeClass == .regular
    // перенастраиваем UI
}

Что ожидать на устройстве: внешний дисплей отдаёт те же size classes, что и любой iPhone; внутренний — regular по обоим измерениям, что как раз и оставляет место под сайдбары и двухколоночные раскладки.

Внутренний дисплей — regular по обоим измерениям, есть место под сайдбар. Изображение: Apple, Tech Talk «Prepare your app for iPhone Duo»

Внутренний дисплей — regular по обоим измерениям, есть место под сайдбар. Изображение: Apple, Tech Talk «Prepare your app for iPhone Duo»

Первоисточник: Apple, Tech Talk «Prepare your app for iPhone Duo» (раздел «Use size classes»).

Изменение 2. Хватит цепляться за главный экран

UIScreen.main на устройстве с двумя дисплеями двусмыслен. Apple прямо говорит: не обращайтесь к «главному экрану» на двухэкранном устройстве — это неоднозначно, и API будет объявлено устаревшим (deprecated). Одного «главного» экрана больше нет.

// Плохо: какой из экранов? Непонятно.
let scale = UIScreen.main.scale
let bounds = UIScreen.main.bounds

// Хорошо: спросите trait collection
let scale = traitCollection.displayScale

// Хорошо: возьмите экран динамически из window scene
let screen = window?.windowScene?.screen

Для размеров под вёрстку опирайтесь на bounds сцены или на окружение (environment), а не на что-либо, выведенное из экрана. Сделайте прямо сейчас поиск по проекту на UIScreen.main — обычно это правка на пять минут и самый вероятный источник странных багов.

Пока вы там: ConcentricRectangle (SwiftUI) и UICornerConfiguration (UIKit) из iOS 26 подстраиваются под реальный радиус скругления экрана вместо захардкоженного cornerRadius: 12.

Первоисточник: Apple, Tech Talk «Prepare your app for iPhone Duo» (разделы «Avoid screen assumptions», «Replace main screen references»).

Изменение 3. Safe area теперь асимметрична

На обычном iPhone левый и правый инсеты совпадают, поэтому куча кода делает так:

// Плохо: предполагает, что обе стороны равны
let width = view.bounds.width - view.safeAreaInsets.left * 2

На iPhone Duo safe area и layout margins часто асимметричны: камера с одной стороны, а в Split View приложение занимает половину дисплея с разными инсетами по краям. Обрабатывайте каждую сторону независимо:

// Хорошо: каждая сторона — отдельно
let width = view.bounds.inset(by: view.safeAreaInsets).width

Общее правило, которое Apple повторяет из доклада в доклад: интерактивный контент переднего плана остаётся внутри safe area; фоновая графика вылезает за её пределы.

// SwiftUI
ZStack {
    BackgroundArtwork()
        .ignoresSafeArea()   // фон: за края
    ControlsView()           // передний план: по умолчанию уважает safe area
}

Стандартные бары (навигация, тулбар, таб-бар) сами раскладываются вне safe area и обходят статус-бар и камеру — их трогать не нужно.

Вертикальные бары: правила раскладки (HIG). На внешнем экране и на внутреннем в ландшафте навигационный и таб-бар встают вертикально; на внутреннем в портрете бары остаются горизонтальными. Иконочные пункты уходят в вертикаль, текстовые остаются горизонтальными. Вверху вертикального бара — Back или Close, следом заметное действие (например, Done).

Асимметричные safe area: камера с одной стороны. Изображение: Apple, Tech Talk «Prepare your app for iPhone Duo»

Асимметричные safe area: камера с одной стороны. Изображение: Apple, Tech Talk «Prepare your app for iPhone Duo»

Первоисточник: Apple, Tech Talks «Prepare your app for iPhone Duo» (раздел «Respect safe areas») и «Raise the bar with iPhone Duo».

Изменение 4. Reserved regions — шарнир и камеры

Это по-настоящему новая концепция. У устройства есть физические особенности, которые «разрезают» дисплей: шарнир (сгиб) и камеры. Apple называет их reserved regions (ReservedRegion в SwiftUI, UIViewReservedRegion в UIKit) — их можно запрашивать, чтобы кастомный UI занял максимум места, не сталкиваясь с системным.

Два вида:

  • .division — сам сгиб. Делит большую область на меньшие. Активен, только когда устройство реально сложено; в плоском состоянии имеет нулевую ширину и неактивен.

  • .occlusion — что-то, лежащее поверх вашего контента. Это подэкранная фронтальная камера.

Как это выглядит в коде Apple (напоминаю: символы pre-release):

// UIKit
let regions = view.reservedRegions(kind: .division)
let frames = regions.map(.frame)   // встраиваем в свой layout
// SwiftUI — division, включая неактивные
GeometryReader { proxy in
    let regions = proxy.reservedRegions(kind: .division, options: .includeInactive)
    let frames = regions.map(.frame)
    // ...
}
// SwiftUI — камера (occlusion)
GeometryReader { proxy in
    let regions = proxy.reservedRegions(kind: .occlusion)
    let frames = regions.map(.frame)
    // ...
}

Неактивные регионы по умолчанию исключаются. Запрашивайте их через options: .includeInactive, когда принимаете структурное решение, которое не должно «дёргаться» при складывании-раскладывании, — например, «всегда держать чётное число колонок в сетке, чтобы ничего не попадало на сгиб».

Когда это вообще нужно: для кастомных, вручную свёрстанных контролов. Стандартные контейнеры — NavigationStack, NavigationSplitView, TabView, List, ScrollView — уже адаптируются к сгибу бесплатно, а система сама переставляет алерты, экшн-шиты, меню и поповеры вокруг reserved regions. Не переизобретайте это.

Проектная тонкость, которую легко упустить: непрерывно скроллящийся контент (статьи, ленты) не должен прыгать, уворачиваясь от сгиба. Смещение (displacement) — для дискретных элементов (кнопка, кластер контролов, контейнер), а не для поверхности чтения.

Как именно смещать (правила из HIG). Apple формулирует смещение как набор правил, а не «двигай как удобно»:

  • что может двигаться независимо — двигается независимо; что связано по смыслу — двигается вместе, чтобы связь между элементами оставалась видимой;

  • движение минимальное: чем дальше уехал элемент, тем слабее его связь с соседями;

  • куда смещать — зависит от позы. В позе «книжка» сгиб вертикальный, регионы слева и справа, элементы (например, алерты) уходят к trailing-краю. На столе или в портрете сгиб горизонтальный, регионы сверху и снизу, интерактивные контролы уезжают в нижнюю половину;

  • скроллящийся контент не смещается.

Reserved regions: сгиб () делит область, подэкранная камера () перекрывает контент. Изображение: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo»

Reserved regions: сгиб () делит область, подэкранная камера () перекрывает контент. Изображение: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo»

Первоисточник: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo» и Human Interface Guidelines: Designing for iPhone Duo.

Изменение 5. Arrangements — новый layout-контейнер

Новое в iOS 27.1. ArrangementView встаёт между вашим навигационным контейнером и контентом, принимает primary и secondary вью и сам решает, как их разместить, исходя из size classes, соотношения сторон и активных division-регионов.

Думайте про «Подкасты»: экран воспроизведения плюс транскрипт. Базовая инициализация — прямо из сэмпла Apple:

// SwiftUI
var body: some View {
    NavigationStack {
        ArrangementView {
            PlayerView()
        } secondary: {
            UpNextView()
        }
    }
}

Два стиля раскладки (точные имена модификаторов стиля — pre-release, сверьте по SDK):

  • split — делит доступные bounds между двумя вью: горизонтально, когда шире, чем выше; вертикально — наоборот.

  • overlay — предпочитает складывать контент друг над/под другом и уходит в side-by-side по мере складывания устройства.

UIKit-эквивалент — UIArrangementViewController.

Как выбрать: если у вас HStack/VStack — это split; если ZStack — overlay. Две грабли: ArrangementView не даёт навигационной инфраструктуры (не вкладывайте в него NavigationSplitView), и не кладите его внутрь List или ScrollView.

Arrangement view: split или overlay в зависимости от доступного места. Изображение: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo»

Arrangement view: split или overlay в зависимости от доступного места. Изображение: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo»

Первоисточник: Apple, Tech Talk «Strike a pose with adaptive layouts on iPhone Duo».

Изменение 6. Hinge API — только для эффектов

Шарнир можно читать напрямую: onHingeChange в SwiftUI, UIHingeInteraction в UIKit. Оба дают грубый статус (закрыто / приоткрыто / полностью открыто) и непрерывный угол.

// Иллюстративно (символы pre-release)
struct InstrumentView: View {
    @State private var pitchBend: Double = 0

    var body: some View {
        GuitarView(pitchBend: pitchBend)
            .onHingeChange { _, context in
                // nil == у устройства нет шарнира. Проверяйте всегда.
                guard let hinge = context.hinge,
                      hinge.status == .partiallyOpen else {
                    pitchBend = 0
                    return
                }
                pitchBend = bend(for: hinge.angle)
            }
    }
}

Этот guard — не вежливость, а необходимость: приложение работает и на всех остальных iPhone, где шарнира нет.

Важная граница, и её Apple проговаривает прямо: hinge-данные наблюдаются вживую и хороши для взаимодействий и эффектов (whammy-бар, параллакс, затвор камеры, реагирующий на сгиб). Для вёрстки используйте arrangements и reserved regions, а не угол шарнира. Если вы считаете фреймы из hinge.angle — вы взяли не тот API.

Первоисточник: Apple, Tech Talk «Leverage multiple displays and scenes on iPhone Duo».

Изменение 7. Несколько сцен и Split View

Впервые на iPhone — два приложения бок о бок. Участвует каждое приложение, вне зависимости от того, опт-инило оно это или нет.

Если вы уже поддерживаете ресайз на iPad или iPhone Mirroring — вы почти у цели: те же инструменты, size classes и геометрия сцены. iPhone Duo — первый iPhone с поддержкой нескольких экземпляров UI вашего приложения, и приложения, у которых это уже работает на iPad, получают её автоматически. Есть ещё новая раскладка, где видео и приложение «стыкуются» вместе, — обрабатывается теми же size classes и scene geometry.

Первоисточник: Apple, Tech Talk «Leverage multiple displays and scenes on iPhone Duo».

Изменение 8. Scene accessories — самое интересное

Scene accessories позволяют выводить контент на оба дисплея одновременно: основной UI внутри, вспомогательный — снаружи.

Флагманский кейс — CameraCaptureAccessory, доступный, когда приложение развёрнуто на весь внутренний экран с активной сессией камеры. Очевидное применение: показать снимаемому человеку его собственный кадр на внешнем экране, пока вы снимаете. Или суфлёр (телепромптер).

Система управляет доступностью динамически (закрыли устройство — аксессуар пропал), поэтому подписывайтесь на изменение доступности и дизейблите свой UI, а не давайте пользователю тыкать в пустоту.

Внешний экран показывает превью снимаемому, пока вы снимаете на внутренний. Изображение: Apple, Tech Talk «Build a great camera experience for iPhone Duo»

Внешний экран показывает превью снимаемому, пока вы снимаете на внутренний. Изображение: Apple, Tech Talk «Build a great camera experience for iPhone Duo»

Первоисточник: Apple, Tech Talk «Build a great camera experience for iPhone Duo».

Отдельный нюанс: Touch ID, а не Face ID

Того, чего нет в большинстве переводных заметок, но что важно для разработчика: у iPhone Duo — Touch ID (боковая кнопка), а не Face ID. Если у вас кастомный UI биометрии (иконки, тексты «посмотрите в камеру» и т.п.), ветвитесь по LAContext.biometryType, иначе покажете пользователю бессмыслицу.

Чеклист (примерно в порядке «усилия и отдача»)

  • Пересобраться под iOS 27.1 SDK

  • Grep по UIScreen.main и заменить

  • Заменить проверки ориентации на size classes

  • Починить допущения о симметрии типа safeAreaInsets.left * 2

  • Перевести кастомную навигацию на NavigationSplitView / TabView

  • Проверить кастомный биометрический UI: ветвление по biometryType

  • Прогнать каждый экран через все четыре позы (когда выйдет симулятор)

  • Аудит центрированных раскладок — не лучше ли двухколоночная?

  • Внедрить ArrangementView для кастомных split/overlay

  • Внедрить reserved regions для самых приоритетных вручную свёрстанных контролов

  • Подумать про hinge API и scene accessories, если у приложения есть реальная причина

Первые четыре — дёшево и спасают от позора. Остальное — там, где настоящая возможность: Duo сделает предельно очевидным, какие приложения получили внимание, а какие нет.

Как тестировать без устройства за $1999

Xcode 27.1 с симулятором iPhone Duo (через Device Hub, с экранными контролами «открыть / закрыть / повернуть / сложить») — это то, чем вы будете реально проверять четыре позы. На момент написания статьи бета ещё не вышла (Apple обещает «позже в этом месяце»), так что пока доступны доклады, гайдлайны и Group Labs с инженерами Apple; полноценный ресайз своего приложения в сгиб появится с бетой. Отдельно тестируйте Split View: половина ширины плюс асимметричные инсеты — там всплывает большинство багов вёрстки.

Источники

Первоисточник — официальные Apple Tech Talks для iPhone Duo и HIG. Весь код в статье показан в их сэмплах; напоминаю, что символы iOS 27.1 пока pre-release (DocC-страниц нет, написание может измениться до релиза SDK):

Плюс страница «Get ready for iPhone Duo» и анонс в Apple Developer News.

Статья написана по мотивам разбора «iPhone Duo for iOS Developers: What Actually Changes in Your Swift Code» с последующей проверкой всех фактов и кода по докладам Apple и актуальным новостям на середину сентября 2026.

Автор: danilabykhovoy

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js