Desarrolladores
Sheets en iPhone Duo: posición con presentationPlacement y esquinas
Cómo funcionan las sheets en iPhone Duo: presentationPlacement para hojas en el borde inicial, final o centradas, y concentricCornerRadii para igualar las esquinas.
Por la redacción de AppleDuoPublicado 9 min de lectura
En esta página
- ¿Dónde aparecen las sheets por defecto en iPhone Duo?
- ¿Cómo se usa presentationPlacement en SwiftUI?
- ¿Qué posición de sheet debería elegir?
- ¿Por qué una sheet se curva en las esquinas de iPhone Duo?
- ¿Cómo igualo las esquinas de la pantalla con concentricCornerRadii?
- ¿Cuándo debería usar UnevenRoundedRectangle?
- ¿Cuáles son los errores habituales con sheets en iPhone Duo?
- Puntos clave
En un iPhone normal, una sheet (hoja) sube desde abajo y ocupa todo el ancho. En iPhone Duo, la presentación de sheets funciona de otra manera: en la gran pantalla interior, una sheet puede flotar en el centro o apoyarse en el borde inicial o final, y su contorno se curva para seguir las esquinas irregulares de la pantalla. Esta guía cubre las API de iOS 27 que controlan dónde aparece una sheet, cómo la trata el sistema en cada postura y cómo alinear tus propias formas redondeadas con el hardware.
Todo lo que aparece aquí procede de la documentación de Apple, de los Tech Talks sobre iPhone Duo, de las respuestas de ingenieros de Apple en los foros para desarrolladores y de publicaciones del desarrollador iOS @sarunw. El equipo de AppleDuo no ha ejecutado este código en hardware. Las API llegaron con iOS 27 y Xcode 27, y los detalles pueden cambiar entre versiones.
¿Dónde aparecen las sheets por defecto en iPhone Duo?
Las sheets se adaptan solas a cada postura. En el Tech Talk Prepare your app for iPhone Duo, Apple explica que las sheets de la pantalla exterior pueden disponer sus botones de barra en vertical y que las sheets de la pantalla interior aparecen centradas. Los popovers, los menús contextuales y las alertas también se adaptan.
Un ingeniero de DTS de Apple añadió más detalles en un hilo de los foros para desarrolladores: todas las sheets se desplazan al borde inicial cuando el dispositivo está plegado y se presentan en el centro cuando la pantalla interior está abierta del todo.
Las barras dentro de una sheet siguen sus propias reglas. El artículo de Apple Preparing your app for iPhone Duo indica que la pantalla exterior presenta por defecto las barras de una sheet en vertical. En la pantalla interior, la barra de herramientas es horizontal en las sheets centradas o en el borde inicial, y vertical en las sheets del borde final.
| Dónde | Posición por defecto de la sheet | Barras dentro de la sheet |
|---|---|---|
| Pantalla exterior (cerrado) | Se adapta automáticamente | Verticales por defecto |
| Pantalla interior, parcialmente plegado | Borde inicial (según DTS de Apple) | Horizontales en posición inicial |
| Pantalla interior, abierto del todo | Centro | Horizontales en posición centrada |
| Pantalla interior, posición final | Borde final (si lo pides) | Verticales |
Si no quieres una barra vertical en una sheet, desactívala con toolbarVerticalBehavior(_:) en SwiftUI o con preferredVerticalBarBehavior en UIKit. Nuestra guía sobre la barra de herramientas vertical de iPhone Duo explica cómo se construyen esas barras y cómo se desbordan los elementos.
¿Cómo se usa presentationPlacement en SwiftUI?
iOS 27 añade el modificador presentationPlacement(_:) y el tipo PresentationPlacement. Lo aplicas al contenido de la sheet, junto a modificadores como presentationDetents. Este es el ejemplo de la documentación de Apple, que deja visible una mayor parte del mapa detrás de la sheet:
Map()
.sheet(isPresented: $isPresented) {
PlaceDetailView()
.presentationDetents([.medium, .large])
.presentationPlacement(.leading)
}
PresentationPlacement tiene cuatro valores estáticos. Apple señala que solo las presentaciones de tipo sheet los respetan; los popovers, las alertas y los menús ignoran el modificador.
| Valor | Qué dice la documentación de Apple |
|---|---|
.automatic | El sistema determina la posición (el valor por defecto) |
.center | Centra la presentación dentro de la vista que la presenta |
.leading | Coloca la presentación en el borde inicial de la vista que la presenta |
.trailing | Coloca la presentación en el borde final de la vista que la presenta |
Inicial y final son términos de dirección de diseño, así que en un idioma de derecha a izquierda .leading debería colocar la sheet a la derecha. Eso es distinto de la barra vertical, que, como señala @sarunw, sigue al hardware y no a la dirección de lectura. Prueba ambas direcciones si tu app está localizada al árabe o al hebreo.
¿Y en UIKit?
En UIKit, define la propiedad preferredPlacement en el UISheetPresentationController del view controller presentado. El artículo de Apple la menciona como el equivalente en UIKit de presentationPlacement(_:), y un Technology Evangelist de Apple la señaló en este hilo del foro como la forma de influir en cómo se adaptan las sheets a la manera en que una persona sostiene el iPhone Duo. Consulta las cabeceras de UIKit en Xcode 27 para ver los nombres exactos de los valores antes de escribir el código.
¿Qué posición de sheet debería elegir?
Empieza con .automatic. El sistema ya mueve las sheets entre el centro y el borde inicial a medida que el dispositivo se pliega, y elige la orientación de barra adecuada en cada caso. Cambia la posición solo cuando tengas un motivo.
Buenos motivos para elegir un lado:
- Mantener visible el contenido principal. El propio ejemplo de Apple usa
.leadingpara una ficha de lugar sobre un mapa. Aplica la misma idea a una sheet tipo inspector junto a una foto, un documento o un tablero de juego. - Alejar la sheet de la barra vertical. En algunas posturas, la pantalla interior coloca las barras a lo largo de un borde. Si tu vista principal ya usa ese borde, una sheet en el lado contrario deja la barra de herramientas al descubierto. Recuerda que una sheet en el borde final recibe su propia barra de herramientas vertical.
- Quedarse junto al contenido que edita la sheet. Una sheet de formato junto al párrafo que modifica es más cómoda que una que lo tapa.
Elige .center para tareas concretas y autocontenidas, como iniciar sesión, un flujo para compartir o un formulario de ajustes, en las que no importa lo que hay detrás de la sheet.
¿Puede cambiar la posición según la postura?
No por sí sola. Un ingeniero de Apple confirmó en los foros que la posición que defines se aplica siempre, no solo al plegar, y que no existe un orden de respaldo del tipo «centro y después final». La solución que propone es detectar una región reservada de división activa y elegir tú la posición:
struct PlaceMapView: View {
@State private var isPresented = true
var body: some View {
GeometryReader { proxy in
// División activa = el pliegue está en uso (parcialmente plegado)
let isFolded = !proxy.reservedRegions(kind: .division).isEmpty
Map()
.sheet(isPresented: $isPresented) {
PlaceDetailView()
.presentationDetents([.medium, .large])
.presentationPlacement(isFolded ? .trailing : .automatic)
}
}
}
}
Esto es un boceto construido a partir de dos API documentadas, reservedRegions(kind:) y presentationPlacement(_:), no código publicado por Apple. Nuestra guía sobre regiones reservadas y el pliegue explica con más detalle las regiones activas e inactivas, y la de estados de la bisagra y onHingeChange cubre cómo escuchar directamente los cambios de postura.
¿Por qué una sheet se curva en las esquinas de iPhone Duo?
Como señala @sarunw, una sheet en iPhone Duo se curva alrededor de las esquinas irregulares del dispositivo. Las sheets del sistema, los popovers y otros contenedores usan esquinas concéntricas: cada curva interior comparte su centro con la curva exterior, de modo que la separación entre ambas se mantiene uniforme en todo el contorno.
Apple dice en el Tech Talk que las API de concentricidad introducidas en iOS 26 se han actualizado para funcionar con las formas de pantalla de iPhone Duo. En SwiftUI eso significa ConcentricRectangle; en UIKit, UICornerConfiguration. El ejemplo de SwiftUI del Tech Talk es una única forma rellena:
ConcentricRectangle()
.fill(Color.green)
.padding(8.0)
.ignoresSafeArea()
Si usas las sheets del sistema y estas formas, obtienes esquinas coincidentes sin esfuerzo. El problema aparece cuando dibujas tus propios paneles con un cornerRadius fijo que se ajustó para otro iPhone.
¿Cómo igualo las esquinas de la pantalla con concentricCornerRadii?
iOS 27 añade concentricCornerRadii a GeometryProxy. A diferencia de ConcentricRectangle, no dibuja nada: devuelve un RectangleCornerRadii? que puedes usar para dibujo personalizado, animaciones o tus propias formas. Un método complementario, concentricCornerRadii(in:), hace lo mismo para un subrectángulo de la vista.
La documentación de Apple da la regla: el radio de cada esquina es el radio de la esquina del contenedor menos la distancia entre la esquina de la vista y la del contenedor. Las esquinas alejadas de las del contenedor reciben cero, y el resultado se limita al radio máximo que puede tener la vista.
@sarunw ofrece un ejemplo práctico: en el iPhone 18 Pro, la esquina de la pantalla mide 62 puntos, así que una vista a 16 puntos de distancia recibe 62 − 16 = 46 puntos. Esa cifra de 62 puntos procede de su publicación; Apple no publica radios de esquina por dispositivo en las páginas que consultamos.
| Esquina de la pantalla | Distancia a la esquina | Radio concéntrico |
|---|---|---|
| 62 pt (iPhone 18 Pro, según @sarunw) | 16 pt | 46 pt |
| 62 pt | 8 pt | 54 pt |
| 62 pt | 62 pt o más | 0 pt |
Las dos últimas filas aplican la fórmula documentada a la misma esquina; no son mediciones independientes. En iPhone Duo las esquinas no son uniformes, que es justo por lo que leer el valor es mejor que fijarlo en el código.
La propiedad devuelve nil cuando no hay una forma de contenedor definida o cuando la forma no aporta suficiente información sobre las esquinas. El ejemplo de Apple define una explícitamente con containerShape(_:). Gestiona siempre nil con un valor de respaldo razonable:
struct FloatingPanel: View {
private let fallback = RectangleCornerRadii(
topLeading: 16, bottomLeading: 16,
bottomTrailing: 16, topTrailing: 16
)
var body: some View {
GeometryReader { proxy in
UnevenRoundedRectangle(
cornerRadii: proxy.concentricCornerRadii ?? fallback,
style: .continuous
)
.fill(.thinMaterial)
}
.padding(16)
.ignoresSafeArea()
}
}
El panel se sitúa a 16 puntos de los bordes, pide al proxy sus radios concéntricos y los dibuja con UnevenRoundedRectangle. Si el sistema no puede resolver una forma de contenedor, el panel recurre a un radio uniforme de 16 puntos.
¿Cuándo debería usar UnevenRoundedRectangle?
UnevenRoundedRectangle dibuja un rectángulo con un radio distinto en cada esquina. No es nuevo en iOS 27 (la documentación de Apple lo sitúa desde iOS 16), pero es el complemento natural de concentricCornerRadii, porque una vista cerca de una esquina de la pantalla necesita un radio grande ahí y uno pequeño en las demás.
Puedes pasar un valor RectangleCornerRadii, como arriba, o indicar cada esquina:
UnevenRoundedRectangle(
topLeadingRadius: 46,
bottomLeadingRadius: 46,
bottomTrailingRadius: 12,
topTrailingRadius: 12,
style: .continuous
)
.fill(.background.secondary)
Esta forma encaja con un panel personalizado fijado al borde inicial: las dos esquinas exteriores siguen la pantalla y las dos interiores se mantienen ajustadas. Es preferible usar los valores calculados por concentricCornerRadii en lugar de números literales como 46, que solo valen para un dispositivo y una distancia concreta.
| Necesidad | Usa | Desde |
|---|---|---|
| Una forma dibujada por el sistema que encaje con su contenedor | ConcentricRectangle | iOS 26 |
| Solo los radios, para dibujo personalizado | GeometryProxy.concentricCornerRadii | iOS 27 |
| Tu propio radio en cada esquina | UnevenRoundedRectangle | iOS 16 (según la documentación de Apple) |
¿Cuáles son los errores habituales con sheets en iPhone Duo?
- Forzar la posición en todas partes. Como una posición fija se aplica en todas las posturas, una sheet que se ve bien medio plegada puede verse rara abierta del todo. Usa
.automaticsalvo que una pantalla necesite otra cosa. - Controladores de presentación personalizados. Una presentación hecha a mano no recibe la adaptación a la postura ni las esquinas concéntricas del sistema. Es preferible usar sheets del sistema con detents.
- Radios de esquina fijos. Un radio copiado de un iPhone anterior no coincidirá con las esquinas de iPhone Duo. Lee
concentricCornerRadiio usaConcentricRectangle. - Márgenes desiguales dentro de la sheet. Junto a una barra vertical, los márgenes varían según el lado. Nuestro artículo sobre áreas seguras y márgenes de contenido cubre
contentMargins(for:edges:). - Herramientas en beta. Un desarrollador informó de un fallo al iniciar («Symbol not found» para
PresentationPlacement.leading) en un dispositivo con Xcode 27 beta 6, incluso con una comprobación de disponibilidad. Ese hilo no tiene una causa confirmada; compila con la versión final de Xcode 27 y un sistema operativo correspondiente antes de depurarlo como si fuera un error tuyo.
Revisa cada sheet en cada postura: cerrado, parcialmente plegado y abierto del todo, en ambas orientaciones. Nuestra checklist para preparar tu app para iPhone Duo recoge el resto de revisiones que vale la pena hacer.
Puntos clave
- En iPhone Duo, las sheets se adaptan por defecto: centradas en la pantalla interior abierta, desplazadas al borde inicial al plegar y con barras verticales en la pantalla exterior.
presentationPlacement(_:)(SwiftUI) ypreferredPlacement(UIKit), ambos nuevos en iOS 27, colocan una sheet en el borde inicial, final o en el centro. Solo las sheets lo respetan, y se aplica en todas las posturas.- Para cambiar la posición según la postura, comprueba si hay una división activa con
reservedRegions(kind:)y elige tú el valor. concentricCornerRadiienGeometryProxy(iOS 27) devuelve radios que comparten centro con las esquinas del contenedor; gestiona el casonil.- Dibuja esos radios con
UnevenRoundedRectangle, o usaConcentricRectanglecuando solo necesites la forma.
A continuación, lee cómo las barras se mueven al borde vertical y luego descubre lo que han creado otros desarrolladores en nuestra colección de juegos creados para el pliegue.
Preguntas frecuentes
¿Cómo coloco una sheet en el lado inicial o final en iPhone Duo?
En SwiftUI, aplica presentationPlacement(.leading) o presentationPlacement(.trailing) al contenido de la sheet. En UIKit, define la propiedad preferredPlacement del UISheetPresentationController del view controller. Solo las presentaciones de tipo sheet respetan esta posición.
¿Dónde aparece una sheet por defecto en iPhone Duo?
Con la posición automática, decide el sistema. Apple dice que las sheets se centran en la pantalla interior, y un ingeniero de Apple explicó en los foros para desarrolladores que se desplazan al borde inicial cuando el dispositivo está plegado y se presentan en el centro cuando la pantalla interior está abierta del todo.
¿Cambia presentationPlacement cuando el dispositivo se pliega?
No. Según un ingeniero de Apple en los foros para desarrolladores, la posición que defines se aplica siempre, no solo al plegar. Para cambiarla según la postura, comprueba si hay una región reservada de división activa y elige tú la posición.
¿Qué devuelve concentricCornerRadii?
Devuelve los radios de esquina que necesita una vista para que sus esquinas compartan centro con las del contenedor, como un valor RectangleCornerRadii. Devuelve nil cuando no hay una forma de contenedor definida o cuando la forma no aporta suficiente información sobre las esquinas. Es nuevo en iOS 27.
¿Qué diferencia hay entre UnevenRoundedRectangle y ConcentricRectangle?
UnevenRoundedRectangle dibuja un rectángulo con los radios que tú indicas para cada esquina. ConcentricRectangle, introducido en iOS 26, calcula por ti las esquinas concéntricas y dibuja la forma. concentricCornerRadii está en medio: solo devuelve los radios, para que los pases a UnevenRoundedRectangle o a un Path.
Fuentes
- presentationPlacement(_:) · Apple Developer Documentation
- PresentationPlacement · Apple Developer Documentation
- Preparing your app for iPhone Duo · Apple Developer Documentation
- Prepare your app for iPhone Duo (Tech Talk) · Apple Developer
- concentricCornerRadii · Apple Developer Documentation
- UnevenRoundedRectangle · Apple Developer Documentation
- Modal on trailing (DTS answer on sheet placement) · Apple Developer Forums
- Controlling sheet presentation across iPhone Duo poses · Apple Developer Forums
- A sheet can sit on the leading side, the trailing side, or the center · @sarunw on X
- The sheet on iPhone Duo curves around the device's uneven corners · @sarunw on X
- iOS 27 adds concentricCornerRadii to GeometryProxy · @sarunw on X
- 62 − 16 = 46: how a concentric corner is calculated · @sarunw on X
- Need a different radius on each corner? Use UnevenRoundedRectangle · @sarunw on X
- The vertical bar follows the hardware, not the reading direction · @sarunw on X
- .presentationPlacement(.leading) does not work! · Apple Developer Forums
Haz que el pliegue forme parte de tu app.
Mostramos apps y juegos que sacan partido de verdad al iPhone Duo. Envíanos la tuya con un enlace al App Store, o mira lo que han creado otros desarrolladores.