Adaptive Layout: kernbegrippen, maatklassen en kwalificatoren

Auteur: IT Sectr Gepubliceerd: 2026-02-26 Leestijd: 10 min

Adaptive Layout — een benadering van interface-ontwerp waarbij de app verschillende lay-outs gebruikt voor verschillende typen apparaten en schermoriëntaties. In tegenstelling tot responsive design schakelt adaptive layout tussen vooraf voorbereide lay-outs op breakpoint-punten. Het artikel behandelt Size Classes en UITraitCollection in iOS, kwalificatoren sw600dp/layout-w600dp in Android en geeft praktische voorbeelden.

Belangrijkste punten

  • Adaptive Layout — discrete schakeling van lay-outs afhankelijk van schermgrootte, oriëntatie en apparaattype
  • Size Classes in iOS classificeren ruimte als Compact of Regular horizontaal en verticaal
  • UITraitCollection — container van iOS-omgevingskenmerken (grootte, schaal, force touch, kleurengamma)
  • sw600dp — Android-kwalificator voor minimale breedte voor tablets (7" en groter)
  • layout-w600dp — kwalificator voor beschikbare breedte die activeert bij voldoende ruimte in de huidige oriëntatie

Wat is Adaptive Layout?

Adaptive Layout — een strategie voor het bouwen van interfaces waarbij de ontwikkelaar aparte lay-outs maakt voor elk apparaattype en schakelt tussen deze op basis van schermkenmerken. In tegenstelling tot responsive design, waar elementen vloeiend stromen, gebruikt adaptive layout discrete schakelingen: telefoon — één lay-out, tablet — een andere, desktop — een derde.

Apple introduceerde Size Classes in iOS 8 (2014) samen met universele apps (universal binaries die zowel op iPhone als iPad werken). Google introduceerde de smallestWidth (swdp) kwalificator in Android 3.2 (2011). Beide mechanismen lossen hetzelfde probleem op: de ontwikkelaar een hulpmiddel geven om verschillende UI's voor verschillende schermen te maken zonder codeduplicatie.

Moderne aanbevelingen van Apple HIG en Google Material Design zijn het erover eens dat adaptive layout verplicht is voor apps die meer dan één schermgrootte ondersteunen. Google Play markeert het ontbreken van aanpassing voor tablets als een tekortkoming. De App Store heeft geen formele vereiste, maar iPad-gebruikers verwachten een native ervaring, niet een uitgerekte iPhone-app.

iOS Size Classes en UITraitCollection

Size Classes — iOS-kenmerk dat de beschikbare ruimte definieert als Compact of Regular op elke as. UITraitCollection — het iOS-systeem voor het doorgeven van omgevingskenmerken door de view-hiërarchie: grootte, schermschaal, force touch capability, kleurengamma (light/dark), accessibility settings.

Apparaat / OriëntatieHorizontalVertical
iPhone portret (alle modellen)CompactRegular
iPhone Plus/Pro Max landschapRegularCompact
iPhone SE / mini landschapCompactCompact
iPad portretRegularRegular
iPad landschapRegularRegular
iPad Split View (1/3 scherm)CompactRegular

UITraitCollection wordt door het systeem gevormd en doorgegeven van UIApplication via UIWindow naar elke UIView. Bij wijziging van oriëntatie of venstergrootte (Split View) genereert het systeem een nieuwe UITraitCollection en roept traitCollectionDidChange aan. In SwiftUI worden wijzigingen gevolgd via Environment Values en wordt de view automatisch opnieuw getekend.

Voorbeeld van adaptieve lay-out in Swift

Aanpassing via UITraitCollection in UIKit wordt geïmplementeerd door te abonneren op trait collection wijzigingen en de lay-out te herbouwen. Het onderstaande voorbeeld toont een controller die schakelt tussen een verticale stack voor iPhone en een split-lay-out voor iPad.

swift
// Adaptieve controller met 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: zijbalk + inhoud
        } else {
            showCompactLayout() // iPhone: tabbalk + 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
    }
}

De methode traitCollectionDidChange wordt aangeroepen bij elke wijziging van traits, maar we controleren alleen horizontalSizeClass — de belangrijkste indicator voor lay-out wijziging. In iOS 17+ wordt aanbevolen om UIViewController.horizontalSizeClass te gebruiken als computed property voor reactieve updates zonder te abonneren op wijzigingen.

Android-kwalificatoren: sw600dp en w600dp

Android biedt twee belangrijke breedte-kwalificatoren: swdp (smallestWidth) en wdp (available width). Het verschil is cruciaal: sw — minimale schermbreedte ongeacht oriëntatie, w — beschikbare breedte rekening houdend met de huidige oriëntatie. sw garandeert dat de lay-out wordt geladen voor een apparaat dat fysiek de opgegeven minimale breedte heeft. w reageert op rotatie — in landschapsmodus kan w600dp activeren, zelfs als in portret de breedte 360 dp is.

KwalificatorVoorwaardeVoorbeeld apparaat
layout-sw600dpMinimale breedte ≥ 600 dpiPad (768 dp), Pixel C (900 dp)
layout-w600dpHuidige breedte ≥ 600 dpiPad in Split View (600 dp), telefoon in landschap
layout-landLandschapsoriëntatieElk apparaat horizontaal gedraaid
layout-sw720dpMinimale breedte ≥ 720 dpiPad Pro (833 dp), Galaxy Tab S9 (800 dp)

Resource hiërarchie in Android: res/layout/activity_main.xml (telefoon), res/layout-sw600dp/activity_main.xml (tablet 7"), res/layout-w600dp-land/activity_main.xml (telefoon in landschap). Android kiest de meest specifieke kwalificator die past bij de huidige apparaatconfiguratie. Bij afwezigheid van een geschikt bestand wordt de basisresource uit res/layout/ gebruikt.

Voorbeeld van adaptieve lay-out in Kotlin

Moderne Android-ontwikkeling gebruikt Jetpack WindowManager om de venstergrootte te bepalen in plaats van directe uitlezing van resources. Dit is vooral belangrijk voor opvouwbare apparaten, waar de schermgrootte dynamisch kan veranderen (Galaxy Fold vouwt uit van 6,2" naar 7,6").

kotlin
// Aanpassing via 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("Telefoon", 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()
    }
}

Het component currentWindowAdaptiveInfo() uit de androidx.window bibliotheek past de interface aan elk apparaat aan: telefoon, tablet, opvouwbaar, ChromeOS. Breedteklassen: COMPACT (0–600 dp), MEDIUM (600–840 dp), EXPANDED (>840 dp). Hoogteklassen: COMPACT (0–480 dp), MEDIUM (480–900 dp), EXPANDED (>900 dp).

Adaptive Layout in SwiftUI

SwiftUI biedt ingebouwde hulpmiddelen voor adaptieve lay-out zonder direct gebruik van Size Classes. AnyLayout, ViewThatFits en GeometryReader maken het mogelijk om interfaces te bouwen die zich automatisch aanpassen aan de beschikbare ruimte.

swift
// SwiftUI-aanpassing via AnyLayout en 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("Favorieten", systemImage: "star")
            Label("Recent", systemImage: "clock")
            Label("Instellingen", systemImage: "gear")
        }
        .padding()
    }
}

// ViewThatFits — automatische lay-outselectie
struct SmartLayout: View {
    var body: some View {
        ViewThatFits {
            HStack { // Prioriteit 1: horizontaal
                CardView()
                CardView()
            }
            VStack { // Als het niet past — verticaal
                CardView()
                CardView()
            }
        }
    }
}

ViewThatFits — een krachtig SwiftUI-hulpmiddel dat automatisch de eerste child-view selecteert die in de beschikbare ruimte past zonder te worden afgesneden. Dit elimineert de noodzaak om expliciet Size Classes te controleren voor eenvoudige adaptieve schakelingen. AnyLayout maakt het mogelijk om het lay-outtype (HStack/VStack) te wijzigen zonder if-else in de body van de view.

Adaptive Layout in Jetpack Compose

Jetpack Compose gebruikt WindowSizeClass (uit de Material 3 adaptive bibliotheek) en BoxWithConstraints voor adaptieve lay-out. In tegenstelling tot XML-kwalificatoren bepaalt Compose de venstergrootte tijdens runtime en herbouwt de UI reactief bij configuratiewijzigingen.

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

        if (width >= 600.dp) {
            // Tablet: twee kolommen (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 {
            // Telefoon: één kolom met navigatie
            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 biedt kant-en-klare componenten: ListDetailScaffold, SupportingPaneScaffold, NavigationSuiteScaffold. Deze componenten passen zich automatisch aan WindowWidthSizeClass aan — schakelen tussen stacked (COMPACT) en side-by-side (MEDIUM/EXPANDED). De ontwikkelaar hoeft alleen het patroon te selecteren en de inhoudspanelen door te geven.

Veelgestelde vragen

Wat is het verschil tussen sw600dp en w600dp?

sw600dp (smallestWidth) — minimale schermbreedte ongeacht oriëntatie. Werkt altijd op tablets van 7"+. w600dp (available width) — beschikbare breedte rekening houdend met de huidige oriëntatie. Werkt op telefoons in landschap, waar de breedte 600 dp kan overschrijden.

Wat is UITraitCollection in iOS?

UITraitCollection — een iOS-object met omgevingskenmerken: size classes (horizontal/vertical), display scale, force touch capability, user interface idiom (iPhone/iPad), color gamut, accessibility settings. Het wordt doorgegeven van UIApplication via de view-hiërarchie en verandert bij wijziging van oriëntatie of venstergrootte.

Hoe pas ik een app aan voor opvouwbare apparaten?

Gebruik Jetpack WindowManager (Android) en UIScreen nativeBounds + traitCollection (iOS). Opvouwbare apparaten veranderen de Size Class bij het uitvouwen. Een architectuur op basis van canonieke lay-outs (list-detail, supporting pane) met reactieve abonnering op venstergroottewijzigingen zonder Activity-herstart wordt aanbevolen.

Moet ik aparte storyboards maken voor iPad?

Nee. Gebruik één storyboard met Size Classes constraint-variaties of programmatische lay-out via UIKit. SwiftUI vereist helemaal geen storyboards. Aparte storyboards voor iPad creëren duplicatie en compliceren onderhoud — het is beter om één lay-out aan te passen via Size Classes.

Wat zijn canonical layouts in Material 3?

Canonical layouts — kant-en-klare adaptieve lay-outpatronen van Google: list-detail (lijst + details), supporting pane (inhoud + actiepaneel), feed (kaarten). Elk patroon ondersteunt drie toestanden (compact/medium/expanded) en is geïmplementeerd in de Material 3 Adaptive bibliotheek via ListDetailScaffold en SupportingPaneScaffold.

Samenvatting

  • Adaptive Layout — discrete schakeling van lay-outs op breakpoint-punten voor verschillende apparaten
  • Size Classes iOS (Compact/Regular) bepalen de lay-out voor iPhone, iPad en Split View
  • UITraitCollection — mechanisme voor het doorgeven van omgevingskenmerken via de view-hiërarchie
  • sw600dp — Android-kwalificator voor minimale breedte voor tablets van 7"+
  • w600dp — kwalificator voor beschikbare breedte die activeert bij rotatie naar landschap
  • Jetpack WindowManager biedt WindowSizeClass (WindowWidthSizeClass: COMPACT/MEDIUM/EXPANDED)
  • Material 3 Adaptive — kant-en-klare componenten met automatische aanpassing (ListDetailScaffold)

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook