Adaptive Layout: conceptos clave, clases de tamaño y calificadores

Autor: IT Sectr Publicado: 2026-02-26 Tiempo de lectura: 10 min

Adaptive Layout es un enfoque de diseño de interfaces donde la aplicación utiliza diferentes diseños para diferentes tipos de dispositivos y orientaciones de pantalla. A diferencia del responsive design, el adaptive layout cambia entre diseños predefinidos en puntos de quiebre. Este artículo analiza Size Classes y UITraitCollection en iOS, los calificadores sw600dp/layout-w600dp en Android y proporciona ejemplos prácticos.

Puntos clave

  • Adaptive Layout — cambio discreto de diseños según el tamaño de pantalla, orientación y tipo de dispositivo
  • Size Classes en iOS clasifican el espacio como Compact o Regular horizontal y verticalmente
  • UITraitCollection — contenedor de características del entorno iOS (tamaño, escala, force touch, gama de colores)
  • sw600dp — calificador Android de ancho mínimo para tablets (7" y más)
  • layout-w600dp — calificador de ancho disponible que se activa cuando hay suficiente espacio en la orientación actual

¿Qué es Adaptive Layout?

Adaptive Layout es una estrategia de UI donde el desarrollador crea diseños separados para cada tipo de dispositivo y cambia entre ellos según las características de la pantalla. A diferencia del responsive design donde los elementos fluyen suavemente, el adaptive layout usa cambios discretos: teléfono — un diseño, tablet — otro, escritorio — un tercero.

Apple introdujo Size Classes en iOS 8 (2014) junto con las aplicaciones universales (binarios que funcionan tanto en iPhone como en iPad). Google presentó el calificador smallestWidth (swdp) en Android 3.2 (2011). Ambos mecanismos resuelven el mismo problema: dar al desarrollador una herramienta para crear diferentes IU para diferentes pantallas sin duplicación de código.

Las guías modernas de Apple HIG y Google Material Design coinciden en que el adaptive layout es esencial para aplicaciones que admiten más de un tamaño de pantalla. Google Play marca la falta de adaptación para tablets como una desventaja. App Store no tiene un requisito formal, pero los usuarios de iPad esperan una experiencia nativa, no una aplicación de iPhone estirada.

Size Classes y UITraitCollection en iOS

Size Classes son una característica de iOS que define el espacio disponible como Compact (Compacto) o Regular (Regular) en cada eje. UITraitCollection es un sistema de iOS para pasar características del entorno a través de la jerarquía de vistas: tamaño, escala de pantalla, capacidad force touch, gama de colores (claro/oscuro), ajustes de accesibilidad.

Dispositivo / OrientaciónHorizontalVertical
iPhone retrato (todos los modelos)CompactRegular
iPhone Plus/Pro Max paisajeRegularCompact
iPhone SE / mini paisajeCompactCompact
iPad retratoRegularRegular
iPad paisajeRegularRegular
iPad Split View (1/3 pantalla)CompactRegular

UITraitCollection es formado por el sistema y se pasa desde UIApplication a través de UIWindow hasta cada UIView. Cuando cambia la orientación o el tamaño de la ventana (Split View), el sistema genera un nuevo UITraitCollection y llama a traitCollectionDidChange. En SwiftUI, los cambios se rastrean a través de Environment Values y redibujan la vista automáticamente.

Ejemplo de layout adaptativo en Swift

La adaptación mediante UITraitCollection en UIKit se implementa suscribiéndose a los cambios de trait collection y reconstruyendo el layout. El siguiente ejemplo muestra un controlador que cambia entre una pila vertical para iPhone y un diseño dividido para iPad.

swift
// Controlador adaptativo con Size Classes
import UIKit

final class AdaptiveViewController: UIViewController {

    private let compactStack = UIStackView()
    private let regularStack = UIStackView()
    private let sidebar = UIView()
    private let content = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        updateLayout(for: traitCollection)
    }

    override func traitCollectionDidChange(
        _ previousTraitCollection: UITraitCollection?
    ) {
        super.traitCollectionDidChange(previousTraitCollection)
        if traitCollection.horizontalSizeClass
            != previousTraitCollection?.horizontalSizeClass {
            updateLayout(for: traitCollection)
        }
    }

    private func updateLayout(for traits: UITraitCollection) {
        if traits.horizontalSizeClass == .regular {
            showRegularLayout() // iPad: barra lateral + contenido
        } else {
            showCompactLayout() // iPhone: barra de pestañas + push
        }
    }

    private func showRegularLayout() {
        view.subviews.forEach { $0.removeFromSuperview() }
        regularStack.addArrangedSubview(sidebar)
        regularStack.addArrangedSubview(content)
        regularStack.frame = view.bounds
        regularStack.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(regularStack)
    }

    private func showCompactLayout() {
        view.subviews.forEach { $0.removeFromSuperview() }
        compactStack.addArrangedSubview(content)
        compactStack.frame = view.bounds
        compactStack.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(compactStack)
    }

    private func setupViews() {
        sidebar.backgroundColor = .systemGray6
        content.backgroundColor = .systemBackground
        compactStack.axis = .vertical
        regularStack.axis = .horizontal
    }
}

El método traitCollectionDidChange se llama ante cualquier cambio de traits, pero solo comprobamos horizontalSizeClass — el indicador más significativo para cambiar el diseño. En iOS 17+ se recomienda usar UIViewController.horizontalSizeClass como propiedad computada para actualizaciones reactivas sin suscripción a cambios.

Calificadores Android: sw600dp y w600dp

Android proporciona dos calificadores principales de ancho: swdp (smallestWidth) y wdp (available width). La diferencia es crítica: sw es el ancho mínimo de pantalla independientemente de la orientación, w es el ancho disponible considerando la orientación actual. sw garantiza que el layout se cargue para un dispositivo que físicamente tiene el ancho mínimo especificado. w responde a la rotación — en paisaje, w600dp puede activarse incluso si el ancho en retrato es de 360 dp.

CalificadorCondiciónEjemplo de dispositivo
layout-sw600dpAncho mínimo ≥ 600 dpiPad (768 dp), Pixel C (900 dp)
layout-w600dpAncho actual ≥ 600 dpiPad en Split View (600 dp), teléfono en paisaje
layout-landOrientación landscapeCualquier dispositivo girado horizontalmente
layout-sw720dpAncho mínimo ≥ 720 dpiPad Pro (833 dp), Galaxy Tab S9 (800 dp)

Jerarquía de recursos en Android: res/layout/activity_main.xml (teléfono), res/layout-sw600dp/activity_main.xml (tablet 7"), res/layout-w600dp-land/activity_main.xml (teléfono en paisaje). Android selecciona el calificador más específico que coincida con la configuración actual del dispositivo. Cuando no hay un archivo coincidente, se usa el recurso base de res/layout/.

Ejemplo de layout adaptativo en Kotlin

El desarrollo moderno de Android usa Jetpack WindowManager para determinar el tamaño de la ventana en lugar de leer directamente los recursos. Esto es especialmente importante para dispositivos plegables donde el tamaño de pantalla cambia dinámicamente (Galaxy Fold se despliega de 6.2" a 7.6").

kotlin
// Adaptación mediante Jetpack WindowManager
import androidx.window.core.layout.WindowHeightSizeClass
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun AdaptiveScreen() {
    val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass

    FlowRow(
        verticalAlignment = Arrangement.Top,
        horizontalArrangement = when (windowSizeClass.windowWidthSizeClass) {
            WindowWidthSizeClass.EXPANDED -> Arrangement.SpaceEvenly
            else -> Arrangement.Start
        }
    ) {
        when (windowSizeClass.windowWidthSizeClass) {
            WindowWidthSizeClass.COMPACT -> {
                CompactContent()
            }
            WindowWidthSizeClass.MEDIUM -> {
                MediumContent()
            }
            WindowWidthSizeClass.EXPANDED -> {
                ExpandedContent()
            }
        }
    }
}

@Composable
private fun CompactContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text("Teléfono", style = MaterialTheme.typography.headlineSmall)
        ListContent()
    }
}

@Composable
private fun MediumContent() {
    Row(modifier = Modifier.padding(24.dp)) {
        NavigationRail { ... }
        Column { ListContent() }
    }
}

@Composable
private fun ExpandedContent() {
    Row(modifier = Modifier.padding(32.dp)) {
        PermanentNavigationDrawer { ... }
        Column {
            ListContent()
        }
        DetailPane()
    }
}

El componente currentWindowAdaptiveInfo() de la biblioteca androidx.window adapta la interfaz a cualquier dispositivo: teléfono, tablet, plegable, ChromeOS. Clases de ancho: COMPACT (0–600 dp), MEDIUM (600–840 dp), EXPANDED (>840 dp). Clases de alto: COMPACT (0–480 dp), MEDIUM (480–900 dp), EXPANDED (>900 dp).

Adaptive Layout en SwiftUI

SwiftUI proporciona herramientas integradas para el layout adaptativo sin usar directamente Size Classes. AnyLayout, ViewThatFits y GeometryReader permiten construir interfaces que se ajustan automáticamente al espacio disponible.

swift
// Adaptación SwiftUI mediante AnyLayout y ViewThatFits
import SwiftUI

struct AdaptiveGrid: View {
    @Environment(\.horizontalSizeClass) private var hSizeClass

    var body: some View {
        let layout = hSizeClass == .regular
            ? AnyLayout(HStackLayout())
            : AnyLayout(VStackLayout())

        layout {
            Label("Favoritos", systemImage: "star")
            Label("Recientes", systemImage: "clock")
            Label("Ajustes", systemImage: "gear")
        }
        .padding()
    }
}

// ViewThatFits — selección automática de layout
struct SmartLayout: View {
    var body: some View {
        ViewThatFits {
            HStack { // Prioridad 1: horizontal
                CardView()
                CardView()
            }
            VStack { // Si no cabe — vertical
                CardView()
                CardView()
            }
        }
    }
}

ViewThatFits es una potente herramienta de SwiftUI que selecciona automáticamente la primera vista hija que cabe en el espacio disponible sin recortar. Esto elimina la necesidad de verificar explícitamente Size Classes para cambios adaptativos simples. AnyLayout permite cambiar el tipo de layout (HStack/VStack) sin if-else en el cuerpo de la vista.

Adaptive Layout en Jetpack Compose

Jetpack Compose usa WindowSizeClass (de la biblioteca Material 3 adaptive) y BoxWithConstraints para el diseño adaptativo. A diferencia de los calificadores XML, Compose determina el tamaño de la ventana en tiempo de ejecución y recompone la IU reactivamente ante cambios de configuración.

kotlin
// Jetpack Compose adaptativo mediante BoxWithConstraints
@Composable
fun AdaptiveList(items: List<String>) {
    BoxWithConstraints {
        val width = maxWidth

        if (width >= 600.dp) {
            // Tablet: dos columnas (list-detail)
            Row(modifier = Modifier.fillMaxSize()) {
                LazyColumn(modifier = Modifier.weight(1f)) {
                    items(items) { item ->
                        ListItem(text = item)
                    }
                }
                var selected by remember { mutableStateOf(items.first()) }
                DetailPanel(item = selected)
                    .weight(2f)
            }
        } else {
            // Teléfono: una columna con navegación
            LazyColumn(modifier = Modifier.fillMaxSize()) {
                items(items) { item ->
                    ListItem(text = item, onClick = { navigateToDetail(item) })
                }
            }
        }
    }
}

@Composable
fun AdaptiveListMaterial3() {
    val windowClass = currentWindowAdaptiveInfo().windowSizeClass

    AdaptiveLayout(
        layout = windowClass.windowWidthSizeClass
    ) {
        when (windowClass.windowWidthSizeClass) {
            WindowWidthSizeClass.COMPACT -> {
                ListDetailScaffold(
                    isDetailOnly = false,
                    list = { ListPane() },
                    detail = { DetailPane() }
                )
            }
            else -> {
                ListDetailScaffold(
                    isDetailOnly = false,
                    list = { ListPane() },
                    detail = { DetailPane() }
                )
            }
        }
    }
}

Material 3 Adaptive Layouts proporciona componentes listos: ListDetailScaffold, SupportingPaneScaffold, NavigationSuiteScaffold. Estos componentes se adaptan automáticamente a WindowWidthSizeClass — cambian entre apilado (COMPACT) y lado a lado (MEDIUM/EXPANDED). El desarrollador solo necesita elegir un patrón y pasar los paneles de contenido.

Preguntas frecuentes

¿Cuál es la diferencia entre sw600dp y w600dp?

sw600dp (smallestWidth) — ancho mínimo de pantalla independientemente de la orientación. Se activa siempre en tablets de 7"+. w600dp (available width) — ancho disponible considerando la orientación actual. Se activa en teléfonos en paisaje donde el ancho puede superar los 600 dp.

¿Qué es UITraitCollection en iOS?

UITraitCollection es un objeto de iOS que contiene características del entorno: size classes (horizontal/vertical), escala de pantalla, capacidad force touch, idiom de interfaz de usuario (iPhone/iPad), gama de colores, ajustes de accesibilidad. Se pasa desde UIApplication a través de la jerarquía de vistas y cambia al modificar la orientación o el tamaño de la ventana.

¿Cómo adaptar una aplicación para dispositivos plegables?

Use Jetpack WindowManager (Android) y UIScreen nativeBounds + traitCollection (iOS). Los dispositivos plegables cambian Size Class al desplegarse. Se recomienda una arquitectura basada en layouts canónicos (list-detail, supporting pane) con suscripción reactiva a cambios de tamaño de ventana sin reiniciar la Activity.

¿Necesito crear storyboards separados para iPad?

No. Use un único storyboard con variaciones de constraints por Size Class o layout programático mediante UIKit. SwiftUI no requiere storyboards en absoluto. Los storyboards separados para iPad crean duplicación y complican el mantenimiento — es mejor adaptar un solo layout mediante Size Classes.

¿Qué son los canonical layouts en Material 3?

Canonical layouts son patrones de diseño adaptativo prefabricados de Google: list-detail (lista + detalle), supporting pane (contenido + panel de acciones), feed (tarjetas). Cada patrón admite tres estados (compact/medium/expanded) y está implementado en la biblioteca Material 3 Adaptive mediante ListDetailScaffold y SupportingPaneScaffold.

Resumen

  • Adaptive Layout — cambio discreto de diseños en puntos de quiebre para diferentes dispositivos
  • Size Classes iOS (Compact/Regular) definen el layout para iPhone, iPad y Split View
  • UITraitCollection — mecanismo para pasar características del entorno a través de la jerarquía de vistas
  • sw600dp — calificador Android de ancho mínimo para tablets de 7"+
  • w600dp — calificador de ancho disponible que se activa al girar a paisaje
  • Jetpack WindowManager proporciona WindowSizeClass (WindowWidthSizeClass: COMPACT/MEDIUM/EXPANDED)
  • Material 3 Adaptive — componentes listos (ListDetailScaffold) con adaptación automática

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también