onMeasure(): ano ito, mga mode ng MeasureSpec at pag-override ng metodo

May-akda: IT Sectr Nai-publish: 2026-07-22 Oras ng pagbabasa: 9 min

onMeasure() — ay isang protected na metodo ng klase na android.view.View, na tinatawag ng Android system para matukoy ang dimensyon ng View. Ang sistema ay nagpapasa ng dalawang MeasureSpec na bagay sa metodo, bawat isa ay naglalaman ng mode ng pagsukat (EXACTLY, AT_MOST o UNSPECIFIED) at sukat na iminumungkahi ng parent container. Ayon sa Android Developers Documentation (2026), ang pag-override ng onMeasure na may tamang pagproseso ng MeasureSpec ay isang mandatoryong hakbang para sa lahat ng custom na View at ViewGroup na nangangailangan ng tumpak na kontrol sa mga dimensyon.

Mga Pangunahing Puntos

  • onMeasure(int widthMeasureSpec, int heightMeasureSpec) — metodo ng View para sa pagsukat ng dimensyon na may pagpapasa ng MeasureSpec mula sa magulang
  • MeasureSpec — 32-bit na halaga na nag-e-encode ng mode ng pagsukat (UNSPECIFIED, EXACTLY, AT_MOST) at sukat
  • setMeasuredDimension(int w, int h) — mandatoryong tawag sa loob ng onMeasure, na nagtatakda ng huling dimensyon ng View
  • Two-pass algorithm ng pagsukat: sinusukat ng magulang ang mga anak, pagkatapos ay nag-uulat ang mga anak ng kanilang dimensyon, at ang magulang ay gumagawa ng pangwakas na desisyon
  • measureChildWithMargins — pantulong na metodo para sa pagsukat ng child View sa custom na ViewGroup

Ano ang onMeasure()?

onMeasure(int widthMeasureSpec, int heightMeasureSpec) — ay ang metodo ng klase na View na tinatawag ng Android system para matukoy ang lapad at taas ng pagpapakita. Ang developer ay nag-o-override ng metodong ito upang ipahiwatig kung anong sukat ang dapat magkaroon ng View batay sa mga limitasyon na ipinasa sa MeasureSpec. Kung walang tamang pag-override ng onMeasure, ang custom na View ay maaaring magpakita nang hindi tama o hindi magpakita nang buo.

Tinatawag ng sistema ang onMeasure sa measure phase ng lifecycle ng View, na nauuna sa mga phase ng layout (onLayout) at draw (onDraw). Kung ang View ay hindi nag-o-override ng onMeasure, ginagamit ang implementasyon mula sa superclass, na nagtatakda ng default na sukat batay sa background drawable o layout_params. Ang tawag na super.onMeasure(widthMeasureSpec, heightMeasureSpec) ay gumagana lamang para sa mga standard na subclass ng View, tulad ng TextView o ImageView.

Ang pangunahing kinakailangan para sa onMeasure — ang tawag na setMeasuredDimension(int, int) ay dapat na mandatoryong naroroon sa dulo ng metodo. Kung ang tawag na ito ay wala, ang sistema ay bumubuo ng IllegalStateException na may mensahe na hindi itinakda ng View ang nasukat na dimensyon. Ang huling dimensyon ay nagiging available sa pamamagitan ng mga getter na getMeasuredWidth() at getMeasuredHeight() pagkatapos ng pagkumpleto ng measure phase.

Mga Mode ng MeasureSpec: tatlong pangunahing halaga

MeasureSpec — ay isang 32-bit na integer, kung saan ang nangungunang 2 bits ay nag-e-encode ng mode ng pagsukat, at ang mas mababang 30 bits — ang sukat. Tinutukoy ng mode kung gaano kalaya ang View sa pagpili ng kanyang sukat. Ang Android ay nagbibigay ng tatlong mode: EXACTLY, AT_MOST, at UNSPECIFIED. Ang bawat mode ay nagdidikta ng ibang lohika ng pagproseso sa onMeasure.

Mode ng MeasureSpecHalagaPag-uugali
EXACTLYTumukoy ang magulang ng eksaktong sukatAng View ay dapat na eksaktong kasya sa ipinasang sukat, kung ayaw nitong lumampas sa mga hangganan
AT_MOSTItinakda ng magulang ang maximum na sukatAng View ay maaaring pumili ng anumang sukat mula 0 hanggang sa ipinasang maximum
UNSPECIFIEDAng magulang ay hindi nagpapataw ng mga limitasyonAng View ay maaaring pumili ng anumang nais na sukat nang walang pang-itaas na limitasyon

Para sa pag-extract ng mode at sukat mula sa MeasureSpec, ginagamit ang mga static na metodo ng klase na MeasureSpec: MeasureSpec.getMode(int) ay nagbabalik ng isa sa tatlong mode (EXACTLY, AT_MOST, UNSPECIFIED), at MeasureSpec.getSize(int) ay nagbabalik ng numerikong sukat sa pixels. Para gumawa ng sariling MeasureSpec, gamitin ang MeasureSpec.makeMeasureSpec(int size, int mode). Ang tatlong metodong ito ay sumasakop sa lahat ng senaryo ng pagtatrabaho sa dimensyon sa onMeasure.

Karaniwang lohika ng pagproseso ng MeasureSpec

Standard pattern ng pagproseso ng MeasureSpec: kung ang mode ay EXACTLY — gamitin ang ipinasang sukat bilang pinal; kung AT_MOST — piliin ang minimum mula sa nais na sukat (nilalaman ng View) at ipinasang maximum; kung UNSPECIFIED — gamitin ang nais na sukat ng View nang walang limitasyon. Ang pattern na ito ay ginagarantiyahan ang tamang pag-uugali sa ilalim ng anumang limitasyon ng magulang.

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)
}

Paggamit ng resolveSize

Para gawing simple ang standard na lohika, ang Android ay nagbibigay ng metodo na resolveSizeAndState, na tumatanggap ng nais na sukat, MeasureSpec at nagbabalik ng huling sukat na may tamang mode. Ang metodong ito ay nag-iimplementa ng pattern na inilarawan sa itaas sa isang linya ng code. Gayundin, available ang function na resolveSize(int size, int measureSpec), na nagbabalik ng purong sukat na walang state bits.

Two-pass algorithm ng pagsukat

Android ay gumagamit ng two-pass algorithm ng pagsukat (two-pass measure), na ginagarantiyahan na ang bawat View sa hierarchy ay tumatanggap ng tamang dimensyon na isinasaalang-alang ang mga limitasyon ng magulang at mga kagustuhan ng mga elementong anak. Sa unang pass, ang magulang ay nagpapasa sa child View ng MeasureSpec na may mga limitasyon, at ang child View ay nagk-compute ng kanilang nais na dimensyon. Sa ikalawang pass, ang magulang ay gumagawa ng pangwakas na desisyon tungkol sa dimensyon.

Para sa ViewGroup, ang proseso ng pagsukat ay mas kumplikado: ang magulang ay dapat munang sukatin ang lahat ng kanyang mga elementong anak, pagkatapos ay tukuyin ang kanyang sariling sukat batay sa kanilang dimensyon. Ang tawag na measureChildren(int widthMeasureSpec, int heightMeasureSpec) ay umiikot sa lahat ng child View at tumatawag para sa bawat isa ng measure(child, childWidthSpec, childHeightSpec). Pagkatapos sukatin ang lahat ng elementong anak, ang ViewGroup ay tumatawag ng setMeasuredDimension na may sarili nitong dimensyon.

Mahalagang nuance: ang metodo na measure (pampubliko, final) ay hindi maaaring i-override — sa halip, ang onMeasure ang ino-override. Ito ay ginagarantiyahan na ang sistema ay maaaring magsagawa ng mga service action bago at pagkatapos ng tawag sa onMeasure, tulad ng pagsuri ng pagbabago ng dimensyon at pagkalkula ng dirty area para sa kasunod na pag-drawing. Kung ang View ay may nakapirming sukat, ang pag-override ng onMeasure ay maaaring hindi kinakailangan.

Banderang MEASURED_SIZE_STATE

MeasureSpec ay hindi lamang kasama ang sukat at mode, kundi pati na rin ang state bits, na accessible sa pamamagitan ng MeasureSpec.getMode(). Pagkatapos ng tawag sa setMeasuredDimension, ang estado ay nagiging bahagi ng nasukat na dimensyon ng View at maaaring suriin sa pamamagitan ng getMeasuredState(). Ito ay ginagamit sa ScrollView at iba pang scrollable na container para sa tamang pagpapasa ng mga limitasyon sa mga anak.

Halimbawa ng pag-override ng onMeasure sa Kotlin

Tingnan natin ang praktikal na halimbawa ng paggawa ng custom na View na may pag-override ng onMeasure para sa parisukat na pagpapakita. Ang klase na SquareView ay nagmamana ng View at ginagarantiyahan na ang lapad at taas ay palaging pantay, anuman ang ipinasang MeasureSpec. Sa onMeasure, tinutukoy ang mas maliit na gilid at itinatakda ang parisukat na sukat.

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)
    }
}

Custom na ViewGroup na may pagsukat ng mga elementong anak

ViewGroup ay nangangailangan ng mas kumplikadong onMeasure logic, dahil una ay sinusukat ang mga elementong anak, pagkatapos ay tinutukoy ang sukat ng ViewGroup mismo. Ang halimbawang CascadeLayout ay namamahagi ng mga elementong anak nang cascade na may spacing. Pagkatapos sukatin ang lahat ng elementong anak sa pamamagitan ng measureChildWithMargins, kinakalkula ang kabuuang lapad at taas.

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
        }
    }
}

Mga karaniwang pagkakamali sa pag-override ng onMeasure

Pag-alis ng tawag sa setMeasuredDimension — ang pinakamadalas na pagkakamali. Kung na-override ng developer ang onMeasure ngunit hindi tinawag ang setMeasuredDimension, ang application ay mag-crash na may IllegalStateException. Ito ay madalas na nangyayari kapag may mga conditional branching sa metodo at sa isa sa mga branch ang tawag ay wala. Ang bawat branch ng code sa onMeasure ay dapat magtapos sa tawag sa setMeasuredDimension.

Pagwawalang-bahala sa AT_MOST mode — ang pangalawang pinakamadalas na pagkakamali. Kung ang View sa AT_MOST mode ay palaging gumagamit ng ipinasang sukat sa halip na pagkalkula batay sa nilalaman, ang parent container ay hindi maaaring maayos na mamahagi ng espasyo. Halimbawa, ang TextView sa AT_MOST ay dapat kalkulahin ang lapad ng teksto at gamitin ang minimum ng nais at ipinasang lapad. Ang pagwawalang-bahala sa AT_MOST ay nagiging sanhi ng View na sakupin ang lahat ng magagamit na espasyo kahit na may maliit na nilalaman.

Paggawa ng mga bagay sa loob ng onMeasure — isang klasikong pagkakamali sa performance. Dahil ang onMeasure ay maaaring tawagin nang maraming beses (sa bawat kahilingan sa layout), ang paggawa ng mga bagay (Paint, Rect, String) sa loob ng metodong ito ay nagkakalat ng memorya at nag-udyok ng garbage collection. Ang lahat ng bagay ay dapat gawin nang isang beses sa constructor ng View, at sa onMeasure ay dapat na isagawa lamang ang lohika ng pagkalkula ng dimensyon. Ang parehong patakaran ay nalalapat sa onDraw at onLayout.

Pagsukat ng child View sa ViewGroup

measureChildWithMargins — ay isang protected na metodo ng ViewGroup na sumusukat ng isang child View na isinasaalang-alang ang MarginLayoutParams nito. Ang metodo ay tumatanggap ng MeasureSpec ng magulang at accumulated na paglipat sa lapad at taas. Awtomatikong inaayos ang MeasureSpec para sa child View, binabawas ang padding ng magulang at margin ng anak, at ipinapasa ang naayos na MeasureSpec sa child.measure().

Para sa advanced na lohika ng pagsukat, ang ViewGroup ay maaaring mag-override ng measureChild(View child, int parentWidthSpec, int parentHeightSpec) o direktang magtrabaho sa MeasureSpec para sa bawat elementong anak. Halimbawa, ang LinearLayout sa onMeasure ay umiikot sa lahat ng child View, sinusukat ang bawat isa na isinasaalang-alang ang layout_weight nito at namamahagi ng natitirang espasyo nang proporsyonal. Ang diskarteng ito ay nagpapahintulot ng implementasyon ng mga arbitraryong layout algorithm.

Caching ng mga resulta ng pagsukat sa pamamagitan ng mekanismo ng measure cache ay available sa pamamagitan ng banderang setMeasureWithLargestChildEnabled sa ilang ViewGroup. Gayunpaman, sa karamihan ng mga kaso, ang onMeasure ay tinatawag muli sa bawat pagbabago ng layout, at ang caching ay hindi inilalapat. Sa custom na ViewGroup, inirerekomenda na bawasan ang mga kalkulasyon sa onMeasure, hindi umasa sa cache.

Mga Madalas na Itanong

Kailangan bang i-override ang onMeasure para sa custom na View?

Oo, kung ang custom na View ay direktang nagmamana mula sa klase na View. Kung ang pagmamana ay mula sa TextView, ImageView, o Button na may kanilang standard na sukat, ang onMeasure ay hindi kailangang i-override. Para sa ViewGroup, ang pag-override ng onMeasure ay palaging kinakailangan — kung hindi, ang mga elementong anak ay hindi masusukat nang tama.

Ano ang mangyayari kung hindi tinawag ang setMeasuredDimension?

Ang Android system ay nagtatapon ng IllegalStateException na may tekstong “The View did not call setMeasuredDimension”. Ang exception na ito ay lumitaw sa metodo na measure() pagkatapos ng pagkumpleto ng onMeasure, kung ang huling dimensyon ay nanatiling zero. Ang exception ay nag-crash ng application kung hindi naproseso sa pamamagitan ng try-catch.

Ano ang pagkakaiba ng getWidth at getMeasuredWidth?

getMeasuredWidth() ay nagbabalik ng sukat na itinakda sa onMeasure (phase ng pagsukat). getWidth() ay nagbabalik ng aktwal na sukat na natanggap ng View sa onLayout pagkatapos isaalang-alang ang lahat ng pagwawasto sa pagpoposisyon. Para sa karamihan ng View, ang mga halagang ito ay magkapareho, ngunit sa custom na ViewGroup ay maaaring magkaiba.

Maaari bang baguhin ang mga animation o estado ng View sa onMeasure?

Hindi, ang onMeasure ay nilayon lamang para sa pagkalkula ng dimensyon. Ang pagbabago ng estado, pagsisimula ng mga animation, pagtatrabaho sa network, o pag-update ng data sa metodong ito ay lumalabag sa arkitektura ng Android at maaaring humantong sa recursive na tawag sa measure, dahil ang pagbabago ng estado ay maaaring mag-trigger ng requestLayout.

Paano nakikipag-ugnayan ang onMeasure sa ConstraintLayout?

ConstraintLayout ay independiyenteng namamahala ng pagsukat ng mga elementong anak batay sa ibinigay na mga limitasyon. Kung ang custom na View sa loob ng ConstraintLayout ay nag-o-override ng onMeasure, dapat nitong iproseso nang tama ang MeasureSpec na ipinasa mula sa ConstraintLayout, kung hindi, ang mga limitasyon ay maaaring hindi gumana. Ang ConstraintLayout ay gumagamit ng two-pass algorithm na may sarili nitong WidgetContainer para sa pagkalkula.

Buod

  • onMeasure() — metodo ng View para sa pagtukoy ng dimensyon, tinatawag ng Android system sa measure phase
  • MeasureSpec nag-e-encode ng mode ng pagsukat (EXACTLY, AT_MOST, UNSPECIFIED) at sukat na ipinasa mula sa magulang
  • setMeasuredDimension — mandatoryong tawag sa dulo ng onMeasure na nagtatakda ng huling dimensyon
  • resolveSize — pantulong na metodo na nag-iimplementa ng standard na lohika ng pagproseso ng MeasureSpec sa isang linya
  • Two-pass algorithm ginagarantiyahan ang tamang pagsukat sa hierarchy ng magulang-anak
  • measureChildWithMargins ay ginagamit para sa pagsukat ng child View sa custom na ViewGroup na isinasaalang-alang ang spacing
  • Ang paggawa ng mga bagay sa loob ng onMeasure ay lubos na hindi inirerekomenda dahil sa panganib ng GC at pagkawala ng frame

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din