onLayout() ViewGroup क्लास की एक विधि है जो पैरेंट कंटेनर के कोऑर्डिनेट प्लेन पर चाइल्ड Views की स्थिति और आकार निर्धारित करती है। Android सिस्टम माप चरण (onMeasure) के बाद onLayout को कॉल करता है, जब प्रत्येक चाइल्ड View के लिए मापी गई चौड़ाई और ऊंचाई पहले से ज्ञात होती है। Android Developers Documentation (2026) के अनुसार, किसी भी कस्टम ViewGroup में onLayout को ओवरराइड करना अनिवार्य है, क्योंकि मानक ViewGroup कार्यान्वयन चाइल्ड का स्वचालित स्थिति निर्धारण नहीं करता है।
मुख्य बिंदु
onLayout(boolean changed, int l, int t, int r, int b) ViewGroup क्लास की एक protected विधि है जिसे सिस्टम पैरेंट कंटेनर के अंदर चाइल्ड Views की स्थिति निर्धारित करने के लिए कॉल करता है। डेवलपर इस विधि को तब ओवरराइड करता है जब वह गैर-मानक एलिमेंट व्यवस्था वाली कस्टम ViewGroup बनाता है: कैस्केड, ग्रिड, शतरंज पैटर्न या मनमाने कोऑर्डिनेट पर। प्रत्येक चाइल्ड View child.layout() के कॉल के माध्यम से अपनी अंतिम सीमाएं प्राप्त करता है।
changed पैरामीटर इंगित करता है कि अंतिम layout के बाद से ViewGroup की स्थिति या आकार बदला है या नहीं। यदि changed सत्य है, तो सभी चाइल्ड एलिमेंट को संभवतः पुनः स्थिति निर्धारण की आवश्यकता है। पैरामीटर l, t, r, b इसके पैरेंट के कोऑर्डिनेट सिस्टम में ViewGroup के ऊपरी-बाएँ और निचले-दाएँ कोनों के कोऑर्डिनेट हैं। onLayout के अंदर, डेवलपर चाइल्ड की व्यवस्था के लिए इन मानों का उपयोग प्रारंभिक कोऑर्डिनेट के रूप में करता है।
ViewGroup एकमात्र वर्ग है जो onLayout को ओवरराइड करता है। एक सामान्य View (ViewGroup नहीं) में चाइल्ड एलिमेंट नहीं होते हैं और इसे onLayout की आवश्यकता नहीं होती है — इसका स्थिति निर्धारण पैरेंट कंटेनर द्वारा संभाला जाता है। भले ही कोई सामान्य View onLayout को ओवरराइड करे, सिस्टम इसे कॉल नहीं करेगा। यह onMeasure से एक मूलभूत अंतर है, जो किसी भी View के लिए कॉल किया जाता है।
लेआउट चरण रूट View पर सार्वजनिक विधि layout(int l, int t, int r, int b) के कॉल से शुरू होता है। यह विधि View की अंतिम कोऑर्डिनेट सेट करती है और यदि View ViewGroup है तो onLayout को कॉल करती है। फिर onLayout प्रत्येक चाइल्ड एलिमेंट के लिए पुनरावर्ती रूप से child.layout() कॉल करता है, और प्रक्रिया पदानुक्रम में नीचे दोहराई जाती है। इस प्रकार, layout जड़ से पत्तियों तक फैलता है।
onLayout को कॉल करने से पहले, सिस्टम जाँचता है कि पिछले चक्र की तुलना में View के आयाम बदले हैं या नहीं। यदि आयाम नहीं बदले हैं और requestLayout कॉल नहीं किया गया है, तो onLayout कॉल नहीं किया जा सकता है — सिस्टम पिछले layout के परिणामों का उपयोग करता है। यह एक अनुकूलन है जो एनिमेशन या स्क्रॉलिंग के दौरान अनावश्यक स्थिति पुनर्गणना को रोकता है, जब केवल सामग्री बदलती है न कि आयाम।
requestLayout() एक View विधि है जो सिस्टम को सूचित करती है कि View का layout पुराना हो गया है और इसे पुनर्गणना की आवश्यकता है। requestLayout को कॉल करने से पूरा चक्र शुरू होता है: पहले onMeasure कॉल किया जाता है, फिर onLayout, फिर onDraw। invalidate के विपरीत, जो केवल पुनर्चित्रण को ट्रिगर करता है, requestLayout आयामों और स्थितियों की पूर्ण पुनर्गणना को ट्रिगर करता है। अत्यधिक कॉल requestLayout के प्रदर्शन समस्याओं का एक सामान्य कारण है।
l (left) — इसके पैरेंट के कोऑर्डिनेट सिस्टम में ViewGroup के बाएँ किनारे का X-कोऑर्डिनेट। t (top) — ऊपरी किनारे का Y-कोऑर्डिनेट। r (right) — दाएँ किनारे का X-कोऑर्डिनेट। b (bottom) — निचले किनारे का Y-कोऑर्डिनेट। ViewGroup की चौड़ाई r - l के रूप में गणना की जाती है, ऊँचाई b - t के रूप में। ये कोऑर्डिनेट पहले से ही ViewGroup के सभी पैडिंग को शामिल करते हैं।
onLayout के अंदर, डेवलपर प्रत्येक चाइल्ड View के लिए child.layout(int childLeft, int childTop, int childRight, int childBottom) कॉल करता है। child.layout में पास किए गए कोऑर्डिनेट पैरेंट ViewGroup के कोऑर्डिनेट सिस्टम में होने चाहिए। आमतौर पर childLeft और childTop की गणना पैरेंट के पैडिंग को ध्यान में रखते हुए की जाती है: childLeft = l + paddingLeft + offsetX, childTop = t + paddingTop + offsetY।
| पैरामीटर | विवरण | सामान्य उपयोग |
|---|---|---|
| l (left) | पैरेंट में ViewGroup के बाएँ किनारे का कोऑर्डिनेट | चाइल्ड एलिमेंट के लिए X-अक्ष पर प्रारंभिक बिंदु |
| t (top) | पैरेंट में ViewGroup के ऊपरी किनारे का कोऑर्डिनेट | चाइल्ड एलिमेंट के लिए Y-अक्ष पर प्रारंभिक बिंदु |
| r (right) | पैरेंट में ViewGroup के दाएँ किनारे का कोऑर्डिनेट | चौड़ाई की ऊपरी सीमा, r - l = getWidth() |
| b (bottom) | पैरेंट में ViewGroup के निचले किनारे का कोऑर्डिनेट | ऊँचाई की ऊपरी सीमा, b - t = getHeight() |
चाइल्ड कोऑर्डिनेट की गणना सूत्र द्वारा की जाती है: childLeft = l + paddingLeft + (marginLeft यदि मौजूद है), childRight = childLeft + child.getMeasuredWidth()। इसी तरह ऊर्ध्वाधर अक्ष के लिए: childTop = t + paddingTop + (marginTop), childBottom = childTop + child.getMeasuredHeight()। इन चार मानों की गणना करने के बाद, child.layout(childLeft, childTop, childRight, childBottom) कॉल किया जाता है।
चलिए एक FlowLayout बनाते हैं — एक कस्टम ViewGroup जो चाइल्ड Views को पंक्तियों में व्यवस्थित करती है, जब वर्तमान पंक्ति भर जाती है तो एलिमेंट को नई पंक्ति में स्थानांतरित करती है। यह एक समतल में wrap के साथ Flexbox का समकक्ष है। onLayout सभी चाइल्ड Views के माध्यम से पुनरावृति करता है, प्रत्येक के लिए स्थिति की गणना करता है, और सही सीमाओं के साथ child.layout() कॉल करता है।
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 और onLayout View जीवनचक्र के दो क्रमिक चरण हैं जो मौलिक रूप से भिन्न कार्य करते हैं। onMeasure View के वांछित (मापे गए) आयाम निर्धारित करता है, जबकि onLayout वास्तविक (अंतिम) कोऑर्डिनेट और आयाम सेट करता है। मुख्य अंतर: onMeasure में, आयाम मध्यवर्ती हो सकते हैं और बाद में पैरेंट द्वारा समायोजित किए जा सकते हैं, जबकि onLayout में प्रत्येक चाइल्ड View की अंतिम स्थिति निर्धारित की जाती है।
onMeasure प्रत्येक View के लिए कॉल किया जाता है, जिसमें लीफ Views (TextView, ImageView, Button) शामिल हैं। onLayout केवल ViewGroup के लिए कॉल किया जाता है। इसका कारण यह है कि स्थिति निर्धारण पैरेंट कंटेनर की जिम्मेदारी है, न कि स्वयं View की। एक लीफ View पैरेंट के onLayout से कॉल किए गए layout() के माध्यम से अपनी स्थिति प्राप्त करता है।
getMeasuredWidth() और getMeasuredHeight() onMeasure के बाद उपलब्ध होते हैं, जबकि getWidth() और getHeight() केवल onLayout के बाद उपलब्ध होते हैं। यदि आप onMeasure के अंदर getWidth() तक पहुँचते हैं, तो यह पिछले चक्र का मान या शून्य लौटाएगा। इसलिए, onMeasure में आयामों की गणना के लिए, आपको MeasureSpec और चाइल्ड का क्रमिक रूप से उपयोग करना चाहिए।
पैडिंग को ध्यान में रखे बिना स्थिति निर्धारण — onLayout को लागू करते समय पहली गलती। डेवलपर अक्सर चाइल्ड Views के प्रारंभिक कोऑर्डिनेट में पैरेंट का paddingLeft और paddingTop जोड़ना भूल जाता है। परिणामस्वरूप, चाइल्ड ViewGroup के किनारे पर प्रदर्शित होते हैं, setPadding() या XML मार्कअप के माध्यम से सेट किए गए पैडिंग को अनदेखा करते हुए। सही गणना: childLeft = paddingLeft + offsetX।
अदृश्य चाइल्ड के लिए layout कॉल करना — दूसरी सामान्य समस्या। यदि ViewGroup में GONE दृश्यता वाले चाइल्ड Views हैं, तो उन्हें स्थिति निर्धारित करने की आवश्यकता नहीं है — वे कोई स्थान नहीं लेते हैं। हालाँकि, onLayout को इस मामले को सही ढंग से संभालना चाहिए, GONE चाइल्ड को छोड़कर। INVISIBLE चाइल्ड के लिए, layout को अभी भी कॉल करने की आवश्यकता है — वे प्रदर्शित न होने पर भी अपना स्थान बनाए रखते हैं।
changed पैरामीटर को अनदेखा करना — तीसरी गलती। changed पैरामीटर इंगित करता है कि ViewGroup के आयाम या स्थिति बदली है या नहीं। यदि changed == false है, तो सभी चाइल्ड एलिमेंट के layout की पुनर्गणना किए बिना कैश्ड कोऑर्डिनेट का उपयोग किया जा सकता है। हालाँकि, पूर्ण layout कैशिंग एक जटिल कार्य है, और अधिकांश कार्यान्वयनों में onLayout प्रत्येक बार बस सभी एलिमेंट की पुनर्गणना करता है। यह कम संख्या में चाइल्ड के साथ स्वीकार्य है।
अक्सर पूछे जाने वाले प्रश्न
हाँ, संभव है यदि ViewGroup मानक LayoutParams का उपयोग करता है और कस्टम स्थिति निर्धारण तर्क नहीं जोड़ता है। हालाँकि, ViewGroup में onLayout का मानक कार्यान्वयन कोई क्रिया नहीं करता है — चाइल्ड एलिमेंट स्थिति निर्धारित नहीं होंगे। व्यवहार में, सभी ViewGroup (LinearLayout, RelativeLayout, FrameLayout) onLayout को ओवरराइड करते हैं।
layout() View की एक सार्वजनिक अंतिम विधि है, जिसे सिस्टम या पैरेंट ViewGroup द्वारा कॉल किया जाता है। यह View के कोऑर्डिनेट सेट करता है और यदि View ViewGroup है तो onLayout कॉल करता है। onLayout() एक संरक्षित विधि है जिसे डेवलपर चाइल्ड एलिमेंट की कस्टम व्यवस्था के लिए ओवरराइड करता है।
तकनीकी रूप से — हाँ, कर सकता है। लेकिन यह स्पष्ट रूप से अनुशंसित नहीं है, क्योंकि यह अनंत पुनरावृत्ति की ओर ले जाता है: requestLayout → onMeasure → onLayout → requestLayout। यदि onLayout के अंदर requestLayout कॉल किया जाता है, तो सिस्टम StackOverflowError अपवाद फेंकेगा। सभी आयाम परिवर्तन onLayout से पहले किए जाने चाहिए।
लेआउट एनिमेशन (LayoutTransition) चाइल्ड View की स्थितियों में परिवर्तन को इंटरसेप्ट करते हैं और ट्रांज़िशन एनिमेशन लागू करते हैं। जब LayoutTransition सक्षम होता है, onLayout पहले अंतिम स्थितियाँ सेट करता है, फिर LayoutTransition पुरानी स्थिति से नई स्थिति में गति को एनिमेट करता है। इसके लिए उचित अंतिम कोऑर्डिनेट के साथ सही onLayout कार्यान्वयन की आवश्यकता होती है।
invalidate() केवल ड्रा चरण (पुनर्चित्रण) को ट्रिगर करता है, measure और layout को प्रभावित किए बिना। onLayout को ट्रिगर करने के लिए, आपको requestLayout() कॉल करने की आवश्यकता है, जो पूरा चक्र आरंभ करता है: measure → layout → draw। invalidate उपस्थिति को अपडेट करने के लिए अधिक कुशल है जब आयाम और स्थितियाँ नहीं बदलती हैं।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें