וואלהפריצה לבית קפה בתל אביב - במהלך יום הכיפוריםThe Jerusalem PostWhat will Israel bring to its most important alliance? - opinionPunchTrump TV goes live as major US networks halt coverageInquirer EntertainmentTaylor Swift will become the most awarded artist in MTV VMAs historyInquirerWoman dies after refusing to leave burning house in QuezonCNN TürkİSTANBULKART 1 TL ÖĞRENCİ ABONMAN BAŞVURUSU 2026| İBB aylık 1 TL öğrenci abonmanı başvurusu nasıl yapılır, kimler başvurabilir?Bollywood HungamaEXCLUSIVE: Ajay Devgn-Rohit Jugraj’s horror thriller titled Surya PrakashSözcüHedef Yatırım'dan yeni açıklamaUOLMercado de carros clássicos muda com novos interesses de colecionadores mais jovensObservador DesportoFragatas. Nuno Melo ouvido no parlamento sobre fragatasהידעןמפת עולם חדשה לחלבונים: בינה מלאכותית מחברת בין רצף, מבנה ומיליארדי שנות אבולוציהn-tvBasketball droht Spaltung: Gierig und planlos: NBA versetzt Europa in Aufruhr
The Daily Newsstand · Free, Always
Tuesday, September 22, 2026

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

Translate

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.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.