onLayout(): ano ito, algorithm ng pagkakalagay at mga parameter ng metodo

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

onLayout() — ay isang metodo ng klase ng ViewGroup na tumutukoy sa mga posisyon at laki ng mga child View sa coordinate plane ng parent container. Tinatawag ng Android system ang onLayout pagkatapos ng phase ng pagsukat (onMeasure), kapag para sa bawat child View ay alam na ang sinusukat na lapad at taas. Ayon sa Android Developers Documentation (2026), ang onLayout ay isang mandatoryong metodo na i-override sa anumang custom na ViewGroup, dahil ang standard na implementasyon ng ViewGroup ay hindi nagsasagawa ng awtomatikong pagpoposisyon ng mga anak.

Mga Pangunahing Punto

  • onLayout(boolean changed, int l, int t, int r, int b) — metodo ng ViewGroup na tumutukoy sa posisyon ng mga child element sa coordinates ng parent
  • child.layout(l, t, r, b) — tawag para sa bawat child View na nagtatakda ng huling hangganan nito
  • Phase ng layout sumusunod pagkatapos ng phase ng measure at bago ang phase ng draw sa lifecycle ng View
  • getWidth() at getHeight() ay magagamit lamang pagkatapos ng pagpapatupad ng onLayout, hindi katulad ng getMeasuredWidth pagkatapos ng onMeasure
  • requestLayout() — metodo na nagpapasimula ng muling pagtawag sa onMeasure at onLayout kapag nagbago ang datos na nakakaapekto sa pagpoposisyon

Ano ang onLayout()?

onLayout(boolean changed, int l, int t, int r, int b) — ay isang protected na metodo ng klase ng ViewGroup na tinatawag ng system para sa pagpoposisyon ng mga child View sa loob ng parent container. Ine-override ng developer ang metodong ito kapag lumilikha ng custom na ViewGroup na may hindi standard na pagkakaayos ng mga elemento: kaskada, grid, pattern ng chessboard, o ayon sa arbitraryong coordinates. Bawat child View ay tumatanggap ng huling hangganan nito sa pamamagitan ng tawag na child.layout().

Ang parameter na changed ay nagpapahiwatig kung ang posisyon o laki ng ViewGroup mismo ay nagbago mula noong huling layout. Kung ang changed ay true, lahat ng child element ay malamang nangangailangan din ng muling pagpoposisyon. Ang mga parameter l, t, r, b ay ang mga coordinates ng kaliwang itaas at kanang ibabang sulok ng ViewGroup sa coordinate system ng kanyang parent. Sa loob ng onLayout, ginagamit ng developer ang mga halagang ito bilang panimulang coordinates para sa pag-aayos ng mga anak.

ViewGroup — ay ang tanging klase na nag-o-override ng onLayout. Ang ordinaryong View (hindi ViewGroup) ay walang mga child element at hindi nangangailangan ng onLayout — ang sarili nitong pagpoposisyon ay pinangangasiwaan ng parent container. Kahit na i-override ng ordinaryong View ang onLayout, hindi ito tatawagin ng system. Ito ang pangunahing pagkakaiba sa pagitan ng onLayout at onMeasure, na tinatawag para sa bawat View.

Daloy ng pagpapatupad ng phase ng layout

Ang phase ng layout ay nagsisimula sa pagtawag ng public na metodo na layout(int l, int t, int r, int b) sa root View. Itinatakda ng metodong ito ang huling coordinates ng View mismo at tinatawag ang onLayout kung ang View ay isang ViewGroup. Pagkatapos ay recursive na tinatawag ng onLayout ang child.layout() para sa bawat child element, at umuulit ang proseso pababa sa hierarchy. Sa ganitong paraan, kumakalat ang layout mula sa ugat patungo sa mga dahon.

Bago ang pagtawag ng onLayout, sinusuri ng system kung ang laki ng View ay nagbago kumpara sa nakaraang cycle. Kung ang laki ay hindi nagbago at ang requestLayout ay hindi tinawag, ang onLayout ay maaaring hindi tawagin — ginagamit ng system ang mga resulta ng nakaraang layout. Ito ay isang optimisasyon na pumipigil sa hindi kinakailangang muling pagkalkula ng mga posisyon sa panahon ng mga animation o scroll, kapag ang nilalaman lamang ang nagbabago, hindi ang laki.

requestLayout() — ay isang metodo ng View na nagpapaalam sa system na ang layout ng View ay luma na at nangangailangan ng muling pagkalkula. Ang pagtawag ng requestLayout ay nagreresulta sa isang kumpletong cycle: una onMeasure ay tinatawag, pagkatapos onLayout, pagkatapos onDraw. Hindi tulad ng invalidate na nagpapasimula lamang ng muling pagguhit, ang requestLayout ay nagpapasimula ng kumpletong muling pagkalkula ng laki at posisyon. Ang labis na pagtawag ng requestLayout ay karaniwang sanhi ng mga problema sa performance.

Mga parameter ng onLayout: l, t, r, b

l (left) — X coordinate ng kaliwang gilid ng ViewGroup sa coordinate system ng kanyang parent. t (top) — Y coordinate ng itaas na gilid. r (right) — X coordinate ng kanang gilid. b (bottom) — Y coordinate ng ibabang gilid. Ang lapad ng ViewGroup ay kinakalkula bilang r - l, taas bilang b - t. Ang mga coordinates na ito ay kasama na ang lahat ng padding ng ViewGroup mismo.

Sa loob ng onLayout, tinatawag ng developer ang child.layout(int childLeft, int childTop, int childRight, int childBottom) para sa bawat child View. Ang coordinates na ipinapasa sa child.layout ay dapat nasa coordinate system ng parent na ViewGroup. Karaniwan, ang childLeft at childTop ay kinakalkula na isinasaalang-alang ang padding ng parent: childLeft = l + paddingLeft + offsetX, childTop = t + paddingTop + offsetY.

ParameterPaglalarawanKaraniwang gamit
l (left)Coordinate ng kaliwang gilid ng ViewGroup sa parentPanimulang punto sa X axis para sa mga child element
t (top)Coordinate ng itaas na gilid ng ViewGroup sa parentPanimulang punto sa Y axis para sa mga child element
r (right)Coordinate ng kanang gilid ng ViewGroup sa parentItaas na hangganan ng lapad, r - l = getWidth()
b (bottom)Coordinate ng ibabang gilid ng ViewGroup sa parentItaas na hangganan ng taas, b - t = getHeight()

Pagkalkula ng coordinates para sa mga child element

Coordinates ng anak ay kinakalkula gamit ang formula: childLeft = l + paddingLeft + (marginLeft if present), childRight = childLeft + child.getMeasuredWidth(). Pareho para sa vertical: childTop = t + paddingTop + (marginTop), childBottom = childTop + child.getMeasuredHeight(). Pagkatapos kalkulahin ang apat na halagang ito, ang child.layout(childLeft, childTop, childRight, childBottom) ay tinatawag.

Halimbawa ng custom na ViewGroup na may onLayout sa Kotlin

Gumawa tayo ng FlowLayout — isang custom na ViewGroup na nag-aayos ng mga child View sa mga hilera, inililipat ang mga elemento sa bagong hilera kapag ang kasalukuyang hilera ay puno. Ito ay analog ng Flexbox na may wrap sa isang eroplano. Inuulit ng onLayout ang lahat ng child View, kinakalkula ang posisyon para sa bawat isa at tinatawag ang child.layout() na may tamang mga hangganan.

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

    private val horizontalSpacing = 12
    private val verticalSpacing = 8

    override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
        val parentWidth =
            MeasureSpec.getSize(widthMeasureSpec)
        var rowX = paddingLeft
        var rowY = paddingTop
        var maxRowHeight = 0

        for (i in 0 until childCount) {
            val child = getChildAt(i)
            measureChildWithMargins(child,
                widthMeasureSpec, 0,
                heightMeasureSpec, 0)

            if (rowX + child.measuredWidth >
                parentWidth - paddingRight) {
                rowX = paddingLeft
                rowY += maxRowHeight + verticalSpacing
                maxRowHeight = 0
            }

            rowX += child.measuredWidth +
                horizontalSpacing
            maxRowHeight = maxOf(maxRowHeight,
                child.measuredHeight)
        }

        val totalHeight = rowY + maxRowHeight +
            paddingBottom
        setMeasuredDimension(
            resolveSize(parentWidth, widthMeasureSpec),
            resolveSize(totalHeight, heightMeasureSpec))
    }

    override fun onLayout(changed: Boolean,
                       l: Int, t: Int,
                       r: Int, b: Int) {
        val parentWidth = r - l
        var rowX = paddingLeft
        var rowY = paddingTop
        var maxRowHeight = 0

        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val cw = child.measuredWidth
            val ch = child.measuredHeight

            if (rowX + cw >
                parentWidth - paddingRight) {
                rowX = paddingLeft
                rowY += maxRowHeight + verticalSpacing
                maxRowHeight = 0
            }

            child.layout(rowX, rowY,
                rowX + cw, rowY + ch)
            rowX += cw + horizontalSpacing
            maxRowHeight =
                maxOf(maxRowHeight, ch)
        }
    }

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

Mga pagkakaiba ng onLayout at onMeasure

onMeasure at onLayout — ay dalawang magkasunod na phase sa lifecycle ng View na gumaganap ng pangunahing magkakaibang mga gawain. Tinutukoy ng onMeasure ang ninanais (measured) na laki ng View, habang ang onLayout ay nagtatakda ng aktwal (actual) na coordinates at laki. Pangunahing pagkakaiba: sa onMeasure, ang laki ay maaaring pansamantala at itinatama mamaya ng parent, samantalang sa onLayout ay inaayos ang huling posisyon ng bawat child View.

onMeasure ay tinatawag para sa bawat View, kabilang ang mga leaf View (TextView, ImageView, Button). onLayout ay tinatawag lamang para sa ViewGroup. Ito ay ipinaliwanag ng katotohanan na ang pagpoposisyon ay responsibilidad ng parent container, hindi ng View mismo. Ang leaf View ay tumatanggap ng posisyon nito sa pamamagitan ng layout() na tinawag mula sa onLayout ng parent.

getMeasuredWidth() at getMeasuredHeight() ay magagamit pagkatapos ng onMeasure, habang ang getWidth() at getHeight() — pagkatapos lamang ng onLayout. Kung ia-access mo ang getWidth() sa loob ng onMeasure, ang halaga mula sa nakaraang cycle o zero ay ibabalik. Kaya't para sa pagkalkula ng laki sa onMeasure, dapat gamitin ang MeasureSpec at sunod-sunod na children.

Karaniwang pagkakamali sa pagtatrabaho sa onLayout

Pagpoposisyon nang hindi isinasaalang-alang ang padding — unang pagkakamali sa pagpapatupad ng onLayout. Madalas kalimutan ng developer na idagdag ang paddingLeft at paddingTop ng parent sa panimulang coordinates ng mga child View. Bilang resulta, ang mga children ay ipinapakita sa gilid ng ViewGroup, hindi pinapansin ang mga espasyo na itinakda sa pamamagitan ng setPadding() o sa XML. Tamang pagkalkula: childLeft = paddingLeft + offsetX.

Pagtawag ng layout para sa mga hindi nakikitang anak — pangalawang karaniwang problema. Kung ang ViewGroup ay naglalaman ng mga child View na may visibility na GONE, hindi na kailangan silang iposisyon — hindi sila kumukuha ng espasyo. Gayunpaman, dapat na tama pangasiwaan ng onLayout ang kasong ito, laktawan ang GONE na mga anak. Para sa INVISIBLE na mga anak, dapat pa ring tawagin ang layout — pinapanatili nila ang kanilang lugar kahit hindi sila ipinapakita.

Pagbalewala sa parameter na changed — ikatlong pagkakamali. Ang parameter na changed ay nagpapahiwatig kung ang laki o posisyon ng ViewGroup ay nagbago. Kung ang changed == false, maaaring gamitin ang naka-cache na coordinates at hindi kalkulahin muli ang layout ng lahat ng child element. Gayunpaman, ang buong caching ng layout ay isang mahirap na gawain at sa karamihan ng implementasyon ng onLayout ay kalkulahin lamang muli ang lahat ng elemento sa bawat pagkakataon. Ito ay katanggap-tanggap kapag kakaunti ang bilang ng mga anak.

Mga Madalas Itanong

Maaari ba akong hindi mag-override ng onLayout sa ViewGroup?

Maaari, kung ang ViewGroup ay gumagamit ng standard na LayoutParams at hindi nagdaragdag ng custom na logic ng pagpoposisyon. Gayunpaman, ang standard na implementasyon ng onLayout sa ViewGroup ay hindi nagsasagawa ng anumang aksyon — ang mga child element ay hindi maipoposisyon. Sa praktika, lahat ng ViewGroup (LinearLayout, RelativeLayout, FrameLayout) ay nag-o-override ng onLayout.

Ano ang pagkakaiba ng layout at onLayout?

layout() — ay isang public final na metodo ng View, na tinatawag ng system o parent na ViewGroup. Itinatakda nito ang coordinates ng View mismo at tinatawag ang onLayout kung ang View ay isang ViewGroup. onLayout() — ay isang protected na metodo na ine-override ng developer para sa custom na pag-aayos ng mga child element.

Maaari bang tumawag ang onLayout ng requestLayout?

Sa teknikal — oo, maaari. Ngunit ito ay lubos na hindi inirerekomenda dahil nagdudulot ito ng walang katapusang recursion: requestLayout → onMeasure → onLayout → requestLayout. Kung ang requestLayout ay tinawag sa loob ng onLayout, ang system ay magtatapon ng StackOverflowError exception. Lahat ng pagbabago sa laki ay dapat gawin bago ang onLayout.

Paano gumagana ang onLayout sa mga animation?

Layout animation (LayoutTransition) ay sumasalo ng mga pagbabago sa posisyon ng mga child View at naglalapat ng transition animation. Kapag naka-on ang LayoutTransition, unang itinatakda ng onLayout ang huling posisyon, pagkatapos ay ine-animate ng LayoutTransition ang paglipat mula sa lumang posisyon patungo sa bago. Ito ay nangangailangan ng tamang implementasyon ng onLayout na may tamang huling coordinates.

Bakit hindi tinatawag ang onLayout pagkatapos ng invalidate?

invalidate() ay nagpapasimula lamang ng phase ng draw (muling pagguhit), hindi naaapektuhan ang measure at layout. Upang ma-trigger ang onLayout, kailangang tawagin ang requestLayout(), na nagpapasimula ng kumpletong cycle: measure → layout → draw. Ang invalidate ay mas mahusay para sa pag-update ng hitsura kapag ang laki at posisyon ay hindi nagbabago.

Buod

  • onLayout() — metodo ng ViewGroup na tumutukoy sa huling posisyon ng mga child View pagkatapos ng pagkumpleto ng phase ng pagsukat
  • child.layout(l, t, r, b) — pangunahing mekanismo ng pagtatakda ng coordinates para sa bawat child element
  • Mga parameter l, t, r, b — coordinates ng mga gilid ng ViewGroup sa parent system, lapad = r - l, taas = b - t
  • Phase ng layout ay kumakalat nang recursive mula sa root View patungo sa mga child element, tinatawag ang onLayout sa bawat ViewGroup
  • requestLayout() ay nagpapasimula ng kumpletong cycle ng muling pagkalkula ng laki at posisyon, hindi tulad ng invalidate na nagpapasimula lamang ng muling pagguhit
  • Pagsasaalang-alang ng padding sa onLayout ay mandatoryo — ang panimulang coordinates ng mga anak ay dapat isama ang paddingLeft at paddingTop ng parent

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