Community생산성 & 협업github.com

expo-duo

iPhone Duo(Apple의 폴더블 아이폰)용 Expo/React Native 앱을 구축, 감사 또는 수정할 때 사용합니다. 수직 레일, 세이프 에어리어 인셋, NativeTabs, SplitView, ArrangementView, expo-hinge, 예약 영역, 방향 고정 및 Duo 자세 테스트(로컬 또는 EAS Workflows CI)를 포함합니다.

expo-duo란 무엇인가요?

이 스킬은 iPhone Duo(Apple의 폴더블 아이폰)용 Expo SDK 58 및 React Native 애플리케이션을 구축하고 최적화하기 위한 포괄적인 가이드입니다. Expo Router의 `Stack`과 `NativeTabs`를 사용하여 시스템 네비게이션을 활용하는 방법, 모든 화면에서 `SafeAreaView`를 사용하여 수평 인셋을 포함하는 방법, 접힘/펼침/회전/Split View 등 모든 자세를 테스트하는 방법 등 네 가지 핵심 규칙을 설명합니다. 주요 API로는 두 개의 콘텐츠 창을 위한 `ArrangementView`, 힌지 각도 및 상태를 위한 `expo-hinge`, 접힘 및 가려짐 영역을 위한 `react-native-reserved-regions`, 레일 가장자리 감지를 위한 `useVerticalBarEdgeIOS` 등이 있으며, 레일 비활성화, 방향 고정 처리, 알려진 제한 사항 및 일반적인 실수와 해결 방법을 다룹니다. 또한 `expo:eas-workflows` 스킬과 연계하여 EAS Workflows CI에서 Duo 시뮬레이터에서 테스트를 실행하는 방법에 대한 지침을 제공합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Andrewi89/Stride-skills/tree/HEAD/plugins/design/skills/expo-duo

Installed? Explore more 생산성 & 협업 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

iPhone Duo의 Expo

출처: https://expo.dev/blog/supporting-iphone-duo (Expo SDK 58). 디자인 규칙은 apple-design-duo에 있습니다. 이 스킬은 Expo 및 React Native 구현 계층입니다. CI 파이프라인 배경: https://docs.expo.dev/tutorial/cicd/introduction/ 및 expo:eas-workflows 스킬을 참조하세요.

요구 사항

  • Expo SDK 58 (iOS 27 대상) 및 Xcode 27.1 (iOS 27.1 런타임 및 iPhone Duo 시뮬레이터).
  • EAS Build 이미지: sdk-58 또는 latest.
  • Xcode 27은 Simulator.app을 Device Hub로 대체합니다 (Xcode > Open Developer Tool > Device Hub). 접히고 회전하며 힌지 각도를 설정할 수 있는 3D Duo가 있습니다.

정신적 모델

접힘 = 컴팩트 너비, 펼침 = 일반 너비. 레이아웃이 넓어지도록 하고, 디자인을 전환하지 마십시오. 양쪽에서 동일한 기능과 상태를 유지합니다. 책과 같은 자세에서는 iOS가 상태 표시줄, 탭 표시줄 및 툴바를 한쪽 가장자리의 수직 레일로 이동합니다.

네 가지 규칙

  1. iOS가 네비게이션을 그리도록 하십시오. Expo Router의 Stack 및 NativeTabs를 사용하십시오. 사용자 정의 JS 헤더와 <TabList>는 레일을 인식하지 못하며 (SDK 58은 최소한의 호환성만 추가), <TabList>는 레일에 들어갈 수 없습니다.
  2. 모든 화면에 SafeAreaView (react-native-safe-area-context) 를 사용하고 수평 인셋을 포함하십시오.
  3. 모든 자세를 테스트하십시오. 접기, 펴기, 회전, Split View.
  4. 필요한 곳에서만 조정하십시오: ArrangementView, preferredPlacement, 예약 영역, 힌지 API 또는 레일 비활성화.

세이프 에어리어 (대부분의 버그가 발생하는 곳)

  • 레일은 왼쪽이나 오른쪽에 84pt 인셋이 필요합니다.
  • 스크롤 콘텐츠를 SafeAreaView edges={['left','right']}로 감싸고, ScrollView를 감싸지 마십시오. 그래야 배경이 가장자리까지 이어집니다. ScrollView에서 contentInsetAdjustmentBehavior="automatic"을 설정하십시오 (RN 패치 #59194는 이 설정만으로 충분하도록 해야 합니다).
  • 수평 캐러셀: 자체적으로 끝 패딩을 추가합니다.
  • 플로팅 버튼 및 토스트: right: insets.right + 16. RTL에서는 left와 right를 모두 읽습니다.
  • NativeTabs 내부에서 insets.bottom은 탭 표시줄이 하단에 있을 때만 포함됩니다. 고정 탭 표시줄 높이를 추가하지 마십시오.
  • 루트 뷰가 아닌 콘텐츠 컨테이너에 인셋으로 패딩을 주십시오.
  • 렌더링 시 useWindowDimensions를 읽으십시오. 왼쪽 Split View 창은 469pt 너비입니다.

Expo Router

  • 레일의 헤더 버튼은 한 열로 쌓이며, 뒤로 또는 닫기가 먼저입니다. 텍스트 전용 항목은 수평을 유지합니다. 사용자 정의 뷰는 제외됩니다.
  • Dynamic Island의 Live Activity는 툴바를 오버플로로 축소할 수 있습니다. 이에 대응하지 마십시오.
  • <SplitView>는 시스템 분할 뷰를 감쌉니다: 접힘 시 한 열, 펼침 시 두 열, 접힘 인식. SDK 58에서 실험적입니다.
  • NativeTabs preferredPlacement: 'sidebar' | 'tabBar' | 'automatic'. 가로 방향에서 열린 디스플레이에 적용됩니다.

추가 API

필요 사항API
두 개의 창 콘텐츠 (iOS 27.1 전용, 이전 버전은 컨테이너 없이 자식을 렌더링)@expo/ui/swift-ui의 ArrangementView, Host 내부에서 ArrangementView.Primary 및 .Secondary 사용. arrangementViewStyle('split' | 'overlay'), splitArrangementLayoutSize, overlayArrangementEdge로 스타일 지정. @expo/ui/swift-ui/modifiers의 modifier.
접힘 및 가려짐 프레임npx expo install react-native-reserved-regions, 이후 useReservedRegions()는 포인트 단위로 { kind: 'division' | 'occlusion', frame }을 반환. 사용자 정의 게임 컨트롤 및 균일 열 그리드에 적합. 접힘 부분에서 콘텐츠를 분할하는 데 사용하지 말고 ArrangementView를 사용하십시오.
힌지 각도 및 상태npx expo install expo-hinge. useHinge(), getHinge(), addHingeListener(). 상태: closed, partiallyOpen, fullyOpen, unknown. SwiftUI modifier onHingeChange는 useWorkletCallback을 통해 UI 스레드에서 실행 가능. Reanimated 및 Android 11+ 폴더블에서 작동.
레일 가장자리useVerticalBarEdgeIOS()는 'leading', 'trailing' 또는 null을 반환. Duo 감지기가 아닙니다 (열린 세로 방향은 null 반환).
레일 비활성화<StatusBar verticalBarBehaviorIOS="disabled" /> (preferredVerticalBarBehavior에 매핑). 비디오 플레이어나 계산기 스타일 화면에만 사용하고, 화면별로 선택을 안정적으로 유지하십시오.

방향

iOS 27에서 방향 고정은 크기 조정 가능한 컨텍스트에서 선호도입니다. lockAsync는 거부될 수 있으며 requireFullScreen은 더 이상 옵트아웃하지 않습니다. Duo에서 세로 또는 가로로 고정하는 것은 앱이 자세 변경을 통해 화면을 채울 때만 작동합니다.

알려진 제한 사항

  • Duo 시뮬레이터에서는 StandBy를 사용할 수 없으며, Xcode 27.1 시뮬레이터에서는 대부분의 앱 확장을 사용할 수 없습니다. 위젯 및 확장은 기기에서 테스트하십시오.
  • expo-app-intents (알파, SDK 58에도 있음)는 Siri, Shortcuts 및 Spotlight에 작업을 노출합니다. 일부 스키마는 해당 도메인보다 최신 iOS가 필요합니다 (.mail.openDraft는 iOS 27 필요). 레이아웃과 관련이 없습니다.

테스트 체크리스트

  • 접힘 상태: 레일 아래에 중요한 것이 없고, 버튼이 응답하는지 확인.
  • 펼침 상태: 레이아웃이 디자인을 전환하지 않고, 레일 아래에 아무것도 없으며, 세로 막대가 상단과 하단으로 돌아오는지 확인.
  • 부분적으로 열림: 접힘 부분에 필수적인 것이 없고, 시트와 팝오버가 한쪽에 위치하는지 확인.
  • Split View: 콘텐츠가 레일 (왼쪽 창의 왼쪽 가장자리)에서 깨끗한지 확인.
  • 화면 중간에서 접기: 스크롤 위치, 상태 및 작업이 유지되는지 확인.
  • 표준 iPhone: 아무것도 변경되지 않는지 확인.

감사 워크플로우

  1. SDK 58 확인 및 재빌드.
  2. 사용자 정의 헤더 또는 탭 표시줄 (headerShown: false 및 수동 빌드된 바, TabList) 검색하여 Stack 및 NativeTabs로 이동.
  3. 하드코딩된 top, bottom, left, right 오프셋, 고정 탭 표시줄 높이 및 루트 수준 패딩 검색. 인셋으로 대체.
  4. 세이프 에어리어 목록에 따라 캐러셀, FAB 및 토스트 확인.
  5. 두 개의 창 화면 선택: SplitView 또는 ArrangementView.
  6. 사용자 정의 레이아웃이 실제로 필요한 경우에만 화면별로 예약 영역 또는 힌지를 결정.
  7. Device Hub에서 확인한 후 CI에서 확인 (아래 참조).

CI: Duo 시뮬레이터에서 실행

expo:eas-workflows 스킬을 사용하십시오 (먼저 라이브 스키마를 가져오고, 작업 매개변수를 추측하지 마십시오). CI/CD 튜토리얼의 적절한 형태: sdk-58 또는 latest 이미지에서 PR 트리거 시뮬레이터 빌드, 선택적 Maestro E2E, 그런 다음 핑거프린트 기반으로 네이티브 빌드와 프로덕션용 EAS Update 중 선택. npx -y eas-cli@latest workflow:validate .eas/workflows/<file>.yml --non-interactive로 검증. 워크플로우는 유료 EAS 분을 사용합니다.

일반적인 실수

실수수정
인셋으로 ScrollView 패딩 처리주변에 SafeAreaView, contentInsetAdjustmentBehavior="automatic"
패딩에 고정 탭 표시줄 높이 사용세이프 에어리어의 insets.bottom 사용
Duo 감지를 위해 useVerticalBarEdgeIOS() 사용레일 가장자리일 뿐이며, 열린 세로 방향에서는 null
예약 영역으로 접힘 부분에서 콘텐츠 분할ArrangementView 또는 SplitView
수동 빌드된 JS 헤더 또는 탭 표시줄Stack 및 NativeTabs
right: 16에 플로팅 버튼right: insets.right + 16
lockAsync가 항상 성공한다고 가정선호도로 처리하고 화면 채우기
표준 iPhone에서만 테스트Device Hub, 모든 자세

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

관련 스킬