onMeasure(): wat is het, MeasureSpec-modi en de methode overschrijven

Auteur: IT Sectr Gepubliceerd: 2026-07-22 Leestijd: 9 min

onMeasure() — is een protected methode van de klasse android.view.View, die door het Android-systeem wordt aangeroepen om de afmetingen van een View te bepalen. Het systeem geeft twee MeasureSpec-objecten aan de methode door, die elk de meetmodus (EXACTLY, AT_MOST of UNSPECIFIED) en de door de bovenliggende container voorgestelde grootte bevatten. Volgens Android Developers Documentation (2026) is het overschrijven van onMeasure met correcte verwerking van MeasureSpec een verplichte stap voor alle aangepaste Views en ViewGroups die nauwkeurige controle over de afmetingen vereisen.

Belangrijkste punten

  • onMeasure(int widthMeasureSpec, int heightMeasureSpec) — View-methode voor het meten van afmetingen met overdracht van MeasureSpec van de ouder
  • MeasureSpec — een 32-bits waarde die de meetmodus (UNSPECIFIED, EXACTLY, AT_MOST) en de grootte codeert
  • setMeasuredDimension(int w, int h) — verplichte aanroep binnen onMeasure die de uiteindelijke afmetingen van de View vastlegt
  • Twee-pass algoritme voor meten: de ouder meet de kinderen, vervolgens rapporteren de kinderen hun afmetingen en neemt de ouder de definitieve beslissing
  • measureChildWithMargins — hulpmethode voor het meten van onderliggende Views in aangepaste ViewGroups

Wat is onMeasure()?

onMeasure(int widthMeasureSpec, int heightMeasureSpec) — is de methode van de klasse View die door het Android-systeem wordt aangeroepen om de breedte en hoogte van de weergave te bepalen. De ontwikkelaar overschrijft deze methode om aan te geven welke grootte de View moet hebben op basis van de beperkingen die in MeasureSpec zijn doorgegeven. Zonder correcte overschrijving van onMeasure kan een aangepaste View onjuist worden weergegeven of helemaal niet worden weergegeven.

Het systeem roept onMeasure aan in de measure-fase van de levenscyclus van een View, die voorafgaat aan de layout- (onLayout) en draw- (onDraw) fasen. Als een View onMeasure niet overschrijft, wordt de implementatie van de superklasse gebruikt, die standaardafmetingen instelt op basis van background drawable of layout_params. De aanroep super.onMeasure(widthMeasureSpec, heightMeasureSpec) werkt alleen voor standaard subklassen van View, zoals TextView of ImageView.

De belangrijkste vereiste voor onMeasure is dat de aanroep van setMeasuredDimension(int, int) verplicht aan het einde van de methode aanwezig moet zijn. Als deze aanroep ontbreekt, genereert het systeem een IllegalStateException met de melding dat de View de gemeten afmetingen niet heeft vastgelegd. De uiteindelijke afmetingen worden beschikbaar via de getters getMeasuredWidth() en getMeasuredHeight() na voltooiing van de measure-fase.

MeasureSpec-modi: drie belangrijke waarden

MeasureSpec — is een 32-bits geheel getal waarin de bovenste 2 bits de meetmodus coderen en de onderste 30 bits de grootte. De modus bepaalt hoe vrij de View is in het kiezen van zijn grootte. Android biedt drie modi: EXACTLY, AT_MOST en UNSPECIFIED. Elke modus dicteert een andere verwerkingslogica in onMeasure.

MeasureSpec-modusWaardeGedrag
EXACTLYOuder heeft exacte grootte gespecificeerdView moet precies in de doorgegeven grootte passen, als het de grenzen niet wil overschrijden
AT_MOSTOuder heeft maximale grootte ingesteldView kan elke grootte kiezen van 0 tot het doorgegeven maximum
UNSPECIFIEDOuder legt geen beperkingen opView kan elke gewenste grootte kiezen zonder bovenste beperkingen

Om de modus en grootte uit MeasureSpec te halen, worden de statische methoden van de klasse MeasureSpec gebruikt: MeasureSpec.getMode(int) retourneert een van de drie modi (EXACTLY, AT_MOST, UNSPECIFIED) en MeasureSpec.getSize(int) retourneert de numerieke grootte in pixels. Om een eigen MeasureSpec te maken wordt MeasureSpec.makeMeasureSpec(int size, int mode) gebruikt. Deze drie methoden dekken alle scenario's voor het werken met afmetingen in onMeasure.

Typische verwerkingslogica van MeasureSpec

Standaard patroon voor het verwerken van MeasureSpec: als de modus EXACTLY is — gebruik de doorgegeven grootte als definitief; als het AT_MOST is — kies het minimum van de gewenste grootte (inhoud van de View) en het doorgegeven maximum; als het UNSPECIFIED is — gebruik de gewenste grootte van de View zonder beperkingen. Dit patroon garandeert correct gedrag onder alle beperkingen van de ouder.

kotlin
override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
    val desiredWidth = 200
    val desiredHeight = 100

    val widthMode = MeasureSpec.getMode(widthMeasureSpec)
    val widthSize = MeasureSpec.getSize(widthMeasureSpec)
    val heightMode = MeasureSpec.getMode(heightMeasureSpec)
    val heightSize = MeasureSpec.getSize(heightMeasureSpec)

    val width = when (widthMode) {
        MeasureSpec.EXACTLY -> widthSize
        MeasureSpec.AT_MOST -> minOf(desiredWidth, widthSize)
        else -> desiredWidth
    }
    val height = when (heightMode) {
        MeasureSpec.EXACTLY -> heightSize
        MeasureSpec.AT_MOST -> minOf(desiredHeight, heightSize)
        else -> desiredHeight
    }
    setMeasuredDimension(width, height)
}

Gebruik van resolveSize

Om de standaardlogica te vereenvoudigen, biedt Android de methode resolveSizeAndState, die de gewenste grootte en MeasureSpec accepteert en de uiteindelijke grootte met de juiste modus retourneert. Deze methode implementeert het hierboven beschreven patroon in één regel code. Ook is de functie resolveSize(int size, int measureSpec) beschikbaar, die de zuivere grootte zonder statusbits retourneert.

Twee-pass meetalgoritme

Android gebruikt een twee-pass meetalgoritme (two-pass measure) dat garandeert dat elke View in de hiërarchie correcte afmetingen krijgt, rekening houdend met de beperkingen van de ouder en de voorkeuren van onderliggende elementen. In de eerste pas geeft de ouder MeasureSpec met beperkingen door aan de onderliggende Views, en de onderliggende Views berekenen hun gewenste afmetingen. In de tweede pas neemt de ouder de definitieve beslissing over de afmetingen.

Voor ViewGroup is het meetproces complexer: de ouder moet eerst al zijn onderliggende elementen meten en vervolgens zijn eigen grootte bepalen op basis van hun afmetingen. De aanroep measureChildren(int widthMeasureSpec, int heightMeasureSpec) doorloopt alle onderliggende Views en roept voor elk measure(child, childWidthSpec, childHeightSpec) aan. Na het meten van alle onderliggende elementen roept ViewGroup setMeasuredDimension aan met zijn eigen afmetingen.

Een belangrijk detail: de methode measure (openbaar, final) kan niet worden overschreven — in plaats daarvan wordt onMeasure overschreven. Dit garandeert dat het systeem serviceacties kan uitvoeren voor en na de aanroep van onMeasure, zoals het controleren van groottewijzigingen en het berekenen van het dirty-gebied voor het daaropvolgende tekenen. Als een View vaste afmetingen heeft, is het overschrijven van onMeasure mogelijk niet nodig.

Vlag MEASURED_SIZE_STATE

MeasureSpec bevat niet alleen de grootte en modus, maar ook statusbits (state bits), toegankelijk via MeasureSpec.getMode(). Na de aanroep van setMeasuredDimension wordt de status onderdeel van de gemeten afmetingen van de View en kan worden gecontroleerd via getMeasuredState(). Dit wordt gebruikt in ScrollView en andere scrollbare containers voor correcte overdracht van beperkingen aan kinderen.

Voorbeeld van onMeasure overschrijven in Kotlin

Laten we een praktisch voorbeeld bekijken van het maken van een aangepaste View met overschrijving van onMeasure voor vierkante weergave. De klasse SquareView erft van View en garandeert dat de breedte en hoogte altijd gelijk zijn, ongeacht de doorgegeven MeasureSpecs. In onMeasure wordt de kleinere zijde bepaald en wordt de vierkante grootte ingesteld.

kotlin
class SquareView(context: Context)
    : View(context) {

    override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
        val widthSize =
            MeasureSpec.getSize(widthMeasureSpec)
        val heightSize =
            MeasureSpec.getSize(heightMeasureSpec)
        val size = minOf(widthSize, heightSize)
        setMeasuredDimension(size, size)
    }
}

Aangepaste ViewGroup met meten van onderliggende elementen

ViewGroup vereist een complexere onMeasure-logica, omdat eerst de onderliggende elementen worden gemeten en vervolgens de grootte van de ViewGroup zelf wordt bepaald. Het voorbeeld CascadeLayout verdeelt onderliggende elementen in een cascade met tussenruimte. Na het meten van alle onderliggende elementen via measureChildWithMargins worden de totale breedte en hoogte berekend.

kotlin
class CascadeLayout(context: Context)
    : ViewGroup(context) {

    private val cascadeOffset = 40

    override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
        var maxWidth = 0
        var totalHeight = 0
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            measureChildWithMargins(child,
                widthMeasureSpec,
                cascadeOffset * i,
                heightMeasureSpec, 0)
            maxWidth = maxOf(maxWidth,
                child.measuredWidth +
                cascadeOffset * i)
            totalHeight += child.measuredHeight
        }
        setMeasuredDimension(
            resolveSize(maxWidth, widthMeasureSpec),
            resolveSize(totalHeight, heightMeasureSpec))
    }

    override fun generateLayoutParams(attrs: AttributeSet?)
        : LayoutParams = MarginLayoutParams(context, attrs)

    override fun onLayout(changed: Boolean,
                       l: Int, t: Int,
                       r: Int, b: Int) {
        var top = t
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val left = l + cascadeOffset * i
            child.layout(left, top,
                left + child.measuredWidth,
                top + child.measuredHeight)
            top += child.measuredHeight
        }
    }
}

Veelgemaakte fouten bij het overschrijven van onMeasure

Het overslaan van de setMeasuredDimension-aanroep — de meest voorkomende fout. Als de ontwikkelaar onMeasure heeft overschreven maar setMeasuredDimension niet heeft aangeroepen, zal de applicatie crashen met IllegalStateException. Dit gebeurt vooral vaak wanneer er voorwaardelijke vertakkingen in de methode zijn en in een van de vertakkingen de aanroep ontbreekt. Elke codetak in onMeasure moet eindigen met een aanroep van setMeasuredDimension.

Het negeren van de AT_MOST-modus — de op een na meest voorkomende fout. Als een View in de AT_MOST-modus altijd de doorgegeven grootte gebruikt in plaats van een berekening op basis van de inhoud, kan de bovenliggende container de ruimte niet correct verdelen. Bijvoorbeeld, een TextView in AT_MOST moet de tekstbreedte berekenen en het minimum van de gewenste en doorgegeven breedte gebruiken. Het negeren van AT_MOST leidt ertoe dat de View alle beschikbare ruimte inneemt, zelfs met kleine inhoud.

Het maken van objecten binnen onMeasure — een klassieke prestatieffout. Omdat onMeasure meerdere keren kan worden aangeroepen (bij elk layout-verzoek), vervuilt het maken van objecten (Paint, Rect, String) binnen deze methode het geheugen en veroorzaakt het garbage collection. Alle objecten moeten eenmalig in de constructor van de View worden gemaakt, en in onMeasure mag alleen de logica voor het berekenen van afmetingen worden uitgevoerd. Dezelfde regel geldt voor onDraw en onLayout.

Meten van onderliggende Views in ViewGroup

measureChildWithMargins — is een protected methode van ViewGroup die één onderliggende View meet, rekening houdend met zijn MarginLayoutParams. De methode accepteert de MeasureSpec van de ouder en de geaccumuleerde verschuivingen in breedte en hoogte. Het past automatisch de MeasureSpec voor de onderliggende View aan, door de padding van de ouder en de margin van het kind af te trekken, en geeft de aangepaste MeasureSpec door aan child.measure().

Voor geavanceerde meetlogica kan ViewGroup measureChild(View child, int parentWidthSpec, int parentHeightSpec) overschrijven of direct met MeasureSpec voor elk onderliggend element werken. Bijvoorbeeld, LinearLayout doorloopt in onMeasure alle onderliggende Views, meet elk met inachtneming van zijn layout_weight en verdeelt de resterende ruimte proportioneel. Deze aanpak maakt het mogelijk om willekeurige lay-outalgoritmen te implementeren.

Caching van meetresultaten via het mechanisme van de meetcache (measure cache) is beschikbaar via de vlag setMeasureWithLargestChildEnabled in bepaalde ViewGroups. In de meeste gevallen wordt onMeasure echter opnieuw aangeroepen bij elke lay-outwijziging en wordt caching niet toegepast. In aangepaste ViewGroups wordt aanbevolen om berekeningen in onMeasure te minimaliseren in plaats van op caching te vertrouwen.

Veelgestelde vragen

Is het verplicht om onMeasure te overschrijven voor een aangepaste View?

Ja, als de aangepaste View rechtstreeks van de klasse View erft. Als de overerving van TextView, ImageView of Button komt met hun standaardafmetingen, hoeft onMeasure niet te worden overschreven. Voor ViewGroup is het overschrijven van onMeasure altijd vereist — anders worden de onderliggende elementen niet correct gemeten.

Wat gebeurt er als setMeasuredDimension niet wordt aangeroepen?

Het Android-systeem gooit een IllegalStateException met de tekst „The View did not call setMeasuredDimension“. Deze uitzondering treedt op in de methode measure() na voltooiing van onMeasure als de uiteindelijke afmetingen nul zijn gebleven. De uitzondering crasht de applicatie als deze niet wordt afgehandeld via try-catch.

Wat is het verschil tussen getWidth en getMeasuredWidth?

getMeasuredWidth() retourneert de grootte die is ingesteld in onMeasure (meetfase). getWidth() retourneert de werkelijke grootte die de View heeft ontvangen in onLayout na het in aanmerking nemen van alle positioneringscorrecties. Voor de meeste Views komen deze waarden overeen, maar in aangepaste ViewGroups kunnen ze verschillen.

Kunnen animaties of de toestand van de View worden gewijzigd in onMeasure?

Nee, onMeasure is uitsluitend bedoeld voor het berekenen van afmetingen. Het wijzigen van de toestand, het starten van animaties, het werken met het netwerk of het bijwerken van gegevens in deze methode schendt de Android-architectuur en kan leiden tot recursieve measure-aanroepen, omdat een toestandswijziging requestLayout kan activeren.

Hoe werkt onMeasure samen met ConstraintLayout?

ConstraintLayout beheert onafhankelijk het meten van onderliggende elementen op basis van gegeven beperkingen. Als een aangepaste View binnen ConstraintLayout onMeasure overschrijft, moet deze de MeasureSpec die van ConstraintLayout is doorgegeven correct verwerken, anders werken de beperkingen mogelijk niet. ConstraintLayout gebruikt een twee-pass algoritme met zijn eigen WidgetContainer voor de berekening.

Samenvatting

  • onMeasure() — View-methode voor het bepalen van afmetingen, aangeroepen door het Android-systeem in de measure-fase
  • MeasureSpec codeert de meetmodus (EXACTLY, AT_MOST, UNSPECIFIED) en de van de ouder doorgegeven grootte
  • setMeasuredDimension — verplichte aanroep aan het einde van onMeasure die de uiteindelijke afmetingen vastlegt
  • resolveSize — hulpmethode die de standaard verwerkingslogica van MeasureSpec in één regel implementeert
  • Twee-pass algoritme garandeert correct meten in de ouder-kindhiërarchie
  • measureChildWithMargins wordt gebruikt voor het meten van onderliggende Views in aangepaste ViewGroups met inachtneming van tussenruimten
  • Het maken van objecten binnen onMeasure wordt ten zeerste afgeraden vanwege het risico op GC en frameverlies

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