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) — 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.
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.
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.
| Parameter | Paglalarawan | Karaniwang gamit |
|---|---|---|
| l (left) | Coordinate ng kaliwang gilid ng ViewGroup sa parent | Panimulang punto sa X axis para sa mga child element |
| t (top) | Coordinate ng itaas na gilid ng ViewGroup sa parent | Panimulang punto sa Y axis para sa mga child element |
| r (right) | Coordinate ng kanang gilid ng ViewGroup sa parent | Itaas na hangganan ng lapad, r - l = getWidth() |
| b (bottom) | Coordinate ng ibabang gilid ng ViewGroup sa parent | Itaas na hangganan ng taas, b - t = getHeight() |
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.
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.
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)
}
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.
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, 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.
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.
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.
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.
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
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.
Basahin din