onMeasure() android.view.View क्लास की एक protected विधि है जिसे Android सिस्टम किसी View के आकार निर्धारित करने के लिए कॉल करता है। सिस्टम इस विधि में दो MeasureSpec ऑब्जेक्ट भेजता है, जिनमें से प्रत्येक में एक मापन मोड (EXACTLY, AT_MOST या UNSPECIFIED) और पैरेंट कंटेनर द्वारा सुझाया गया आकार होता है। Android Developers Documentation (2026) के अनुसार, सटीक आकार नियंत्रण की आवश्यकता वाले सभी कस्टम View और ViewGroup के लिए MeasureSpec के सही हैंडलिंग के साथ onMeasure को ओवरराइड करना अनिवार्य है।
मुख्य बिंदु
onMeasure(int widthMeasureSpec, int heightMeasureSpec) View क्लास की एक विधि है जिसे Android सिस्टम किसी व्यू की चौड़ाई और ऊँचाई निर्धारित करने के लिए कॉल करता है। डेवलपर इस विधि को ओवरराइड करके यह निर्दिष्ट करता है कि MeasureSpec में दी गई बाधाओं के आधार पर View का आकार क्या होना चाहिए। सही onMeasure ओवरराइडिंग के बिना, कस्टम View गलत तरीके से प्रदर्शित हो सकता है या बिल्कुल दिखाई नहीं दे सकता।
सिस्टम View जीवनचक्र के measure चरण के दौरान onMeasure को कॉल करता है, जो layout (onLayout) और draw (onDraw) चरणों से पहले आता है। यदि कोई View onMeasure को ओवरराइड नहीं करता है, तो सुपरक्लास का कार्यान्वयन उपयोग किया जाता है, जो background drawable या layout_params के आधार पर डिफ़ॉल्ट आकार सेट करता है। super.onMeasure(widthMeasureSpec, heightMeasureSpec) को कॉल करना केवल View के मानक उपवर्गों जैसे TextView या ImageView के लिए काम करता है।
onMeasure के लिए एक मुख्य आवश्यकता यह है कि setMeasuredDimension(int, int) का कॉल विधि के अंत में मौजूद होना चाहिए। यदि यह कॉल गायब है, तो सिस्टम IllegalStateException फेंकता है जो बताता है कि View ने मापे गए आयाम निर्धारित नहीं किए। मापन चरण पूरा होने के बाद अंतिम आयाम getMeasuredWidth() और getMeasuredHeight() गेटर्स के माध्यम से उपलब्ध होते हैं।
MeasureSpec एक 32-बिट पूर्णांक है जहाँ शीर्ष 2 बिट मापन मोड को एन्कोड करते हैं और निचले 30 बिट आकार को एन्कोड करते हैं। मोड यह निर्धारित करता है कि View अपना आकार चुनने में कितना स्वतंत्र है। Android तीन मोड प्रदान करता है: EXACTLY, AT_MOST और UNSPECIFIED। प्रत्येक मोड onMeasure में अलग प्रसंस्करण तर्क निर्धारित करता है।
| MeasureSpec मोड | मान | व्यवहार |
|---|---|---|
| EXACTLY | पैरेंट ने सटीक आकार निर्दिष्ट किया | View को दिए गए आकार में बिल्कुल फिट होना चाहिए यदि वह सीमा से बाहर नहीं जाना चाहता |
| AT_MOST | पैरेंट ने अधिकतम आकार सेट किया | View 0 से दिए गए अधिकतम तक कोई भी आकार चुन सकता है |
| UNSPECIFIED | पैरेंट कोई बाधा नहीं लगाता | View बिना किसी ऊपरी सीमा के कोई भी वांछित आकार चुन सकता है |
MeasureSpec से मोड और आकार निकालने के लिए MeasureSpec क्लास की स्थिर विधियों का उपयोग किया जाता है: MeasureSpec.getMode(int) तीन मोड (EXACTLY, AT_MOST, UNSPECIFIED) में से एक लौटाता है, और MeasureSpec.getSize(int) पिक्सल में संख्यात्मक आकार लौटाता है। कस्टम MeasureSpec बनाने के लिए MeasureSpec.makeMeasureSpec(int size, int mode) का उपयोग किया जाता है। ये तीन विधियाँ onMeasure में आकारों के साथ काम करने के सभी परिदृश्यों को कवर करती हैं।
मानक पैटर्न MeasureSpec को संभालने के लिए: यदि मोड EXACTLY है — दिए गए आकार को अंतिम के रूप में उपयोग करें; यदि AT_MOST है — वांछित आकार (View की सामग्री) और दिए गए अधिकतम में से न्यूनतम चुनें; यदि UNSPECIFIED है — बिना किसी बाधा के View का वांछित आकार उपयोग करें। यह पैटर्न पैरेंट की किसी भी बाधा के तहत सही व्यवहार सुनिश्चित करता है।
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)
}
मानक तर्क को सरल बनाने के लिए, Android resolveSizeAndState विधि प्रदान करता है, जो वांछित आकार और MeasureSpec लेता है और सही मोड के साथ अंतिम आकार लौटाता है। यह विधि ऊपर वर्णित पैटर्न को कोड की एक पंक्ति में कार्यान्वित करती है। resolveSize(int size, int measureSpec) फ़ंक्शन भी उपलब्ध है, जो स्टेट बिट्स के बिना एक साफ आकार लौटाता है।
Android दो-पास मापन एल्गोरिदम का उपयोग करता है जो सुनिश्चित करता है कि पदानुक्रम में प्रत्येक View को पैरेंट बाधाओं और चाइल्ड प्राथमिकताओं को ध्यान में रखते हुए सही आयाम मिलते हैं। पहले पास में, पैरेंट चाइल्ड View को बाधाओं के साथ MeasureSpec भेजता है, और चाइल्ड View अपने वांछित आकार की गणना करते हैं। दूसरे पास में, पैरेंट आकारों के बारे में अंतिम निर्णय लेता है।
ViewGroup के लिए, मापन प्रक्रिया अधिक जटिल है: पैरेंट को पहले अपने सभी बच्चों को मापना चाहिए, फिर उनके आकारों के आधार पर अपना स्वयं का आकार निर्धारित करना चाहिए। measureChildren(int widthMeasureSpec, int heightMeasureSpec) को कॉल करना सभी चाइल्ड View के माध्यम से पुनरावृति करता है और प्रत्येक के लिए measure(child, childWidthSpec, childHeightSpec) को कॉल करता है। सभी बच्चों को मापने के बाद, ViewGroup अपने स्वयं के आयामों के साथ setMeasuredDimension को कॉल करता है।
एक महत्वपूर्ण बारीकियाँ: measure विधि (सार्वजनिक, अंतिम) को ओवरराइड नहीं किया जा सकता — इसके बजाय onMeasure को ओवरराइड किया जाता है। यह सुनिश्चित करता है कि सिस्टम onMeasure से पहले और बाद में रखरखाव कार्य कर सकता है, जैसे आकार परिवर्तन की जाँच करना और बाद के ड्राइंग के लिए गंदे क्षेत्र की गणना करना। यदि किसी View के निश्चित आयाम हैं, तो onMeasure को ओवरराइड करना आवश्यक नहीं हो सकता है।
MeasureSpec में न केवल आकार और मोड बल्कि स्टेट बिट्स भी शामिल हैं, जो MeasureSpec.getMode() के माध्यम से सुलभ हैं। setMeasuredDimension को कॉल करने के बाद, स्थिति View के मापे गए आयामों का हिस्सा बन जाती है और getMeasuredState() के माध्यम से जाँची जा सकती है। इसका उपयोग ScrollView और अन्य स्क्रॉल करने योग्य कंटेनरों में बच्चों को बाधाओं को सही ढंग से भेजने के लिए किया जाता है।
आइए वर्गाकार प्रदर्शन के लिए onMeasure के साथ एक कस्टम View बनाने का व्यावहारिक उदाहरण देखें। SquareView क्लास View का विस्तार करती है और सुनिश्चित करती है कि चौड़ाई और ऊँचाई हमेशा बराबर हों, भले ही भेजा गया MeasureSpec कुछ भी हो। onMeasure में, न्यूनतम भुजा निर्धारित की जाती है और वर्गाकार आकार सेट किया जाता है।
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)
}
}
ViewGroup को अधिक जटिल onMeasure तर्क की आवश्यकता होती है क्योंकि पहले बच्चों को मापा जाना चाहिए, फिर ViewGroup का अपना आकार निर्धारित किया जाता है। CascadeLayout उदाहरण बच्चों को एक ऑफसेट के साथ कैस्केड में वितरित करता है। measureChildWithMargins के माध्यम से सभी बच्चों को मापने के बाद, कुल चौड़ाई और ऊँचाई की गणना की जाती है।
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
}
}
}
setMeasuredDimension कॉल का छूट जाना सबसे आम गलती है। यदि डेवलपर onMeasure को ओवरराइड करता है लेकिन setMeasuredDimension को कॉल नहीं करता है, तो एप्लिकेशन IllegalStateException के साथ क्रैश हो जाता है। यह विशेष रूप से तब होता है जब विधि में सशर्त शाखाएँ हों और एक शाखा में कॉल गायब हो। onMeasure में कोड की प्रत्येक शाखा setMeasuredDimension कॉल के साथ समाप्त होनी चाहिए।
AT_MOST मोड को अनदेखा करना दूसरी सबसे आम गलती है। यदि कोई View AT_MOST मोड में सामग्री के आधार पर गणना करने के बजाय हमेशा भेजे गए आकार का उपयोग करता है, तो पैरेंट कंटेनर स्थान को सही ढंग से वितरित नहीं कर सकता। उदाहरण के लिए, AT_MOST में TextView को टेक्स्ट की चौड़ाई की गणना करनी चाहिए और वांछित और भेजी गई चौड़ाई में से न्यूनतम का उपयोग करना चाहिए। AT_MOST को अनदेखा करने से View छोटी सामग्री होने पर भी सभी उपलब्ध स्थान घेर लेता है।
onMeasure के अंदर ऑब्जेक्ट बनाना एक क्लासिक प्रदर्शन गलती है। चूँकि onMeasure को कई बार कॉल किया जा सकता है (प्रत्येक layout अनुरोध पर), इस विधि के अंदर ऑब्जेक्ट (Paint, Rect, String) बनाना मेमोरी को अव्यवस्थित करता है और कचरा संग्रहण को ट्रिगर करता है। सभी ऑब्जेक्ट View कंस्ट्रक्टर में एक बार बनाए जाने चाहिए, और onMeasure में केवल आकार गणना तर्क चलना चाहिए। यही नियम onDraw और onLayout पर भी लागू होता है।
measureChildWithMargins ViewGroup की एक संरक्षित विधि है जो एक एकल चाइल्ड View को उसके MarginLayoutParams को ध्यान में रखते हुए मापती है। विधि पैरेंट का MeasureSpec और संचित चौड़ाई और ऊँचाई ऑफ़सेट स्वीकार करती है। यह पैरेंट के पैडिंग और चाइल्ड के मार्जिन को घटाकर चाइल्ड View के लिए MeasureSpec को स्वचालित रूप से समायोजित करती है, फिर समायोजित MeasureSpec को child.measure() में भेजती है।
उन्नत मापन तर्क के लिए, ViewGroup measureChild(View child, int parentWidthSpec, int parentHeightSpec) को ओवरराइड कर सकता है या प्रत्येक बच्चे के लिए सीधे MeasureSpec के साथ काम कर सकता है। उदाहरण के लिए, LinearLayout onMeasure में सभी चाइल्ड View के माध्यम से पुनरावृति करता है, प्रत्येक को उसके layout_weight को ध्यान में रखते हुए मापता है और शेष स्थान को आनुपातिक रूप से वितरित करता है। यह दृष्टिकोण मनमाना लेआउट एल्गोरिदम को लागू करने की अनुमति देता है।
माप कैश तंत्र के माध्यम से मापन परिणामों को कैश करना निश्चित ViewGroup में setMeasureWithLargestChildEnabled फ़्लैग के माध्यम से उपलब्ध है। हालाँकि, अधिकांश मामलों में onMeasure को किसी भी layout परिवर्तन पर फिर से कॉल किया जाता है, और कैशिंग लागू नहीं होती है। कस्टम ViewGroup में, कैशिंग पर निर्भर रहने के बजाय onMeasure में गणनाओं को कम करने की सिफारिश की जाती है।
अक्सर पूछे जाने वाले प्रश्न
हाँ, यदि कस्टम View सीधे View क्लास से इनहेरिट करता है। यदि यह TextView, ImageView या Button से उनके मानक आकारों के साथ इनहेरिट करता है, तो onMeasure को अपरिवर्तित छोड़ा जा सकता है। ViewGroup के लिए, onMeasure को ओवरराइड करना हमेशा आवश्यक है — अन्यथा बच्चे सही ढंग से नहीं मापे जाएँगे।
Android सिस्टम IllegalStateException फेंकता है जिसमें संदेश “The View did not call setMeasuredDimension” होता है। यह अपवाद measure() विधि में onMeasure पूरा होने के बाद होता है, यदि अंतिम आयाम शून्य रह गए हों। यदि try-catch के माध्यम से नहीं संभाला जाता है तो अपवाद एप्लिकेशन को क्रैश कर देता है।
getMeasuredWidth() onMeasure (मापन चरण) में निर्धारित आकार लौटाता है। getWidth() वास्तविक आकार लौटाता है जो View को onLayout में सभी स्थिति समायोजन के बाद मिला। अधिकांश View के लिए ये मान मेल खाते हैं, लेकिन कस्टम ViewGroup में ये भिन्न हो सकते हैं।
नहीं, onMeasure विशेष रूप से आकार गणना के लिए है। इस विधि में स्थिति बदलना, एनिमेशन शुरू करना, नेटवर्किंग या डेटा अपडेट करना Android आर्किटेक्चर का उल्लंघन करता है और पुनरावर्ती measure कॉल का कारण बन सकता है, क्योंकि स्थिति परिवर्तन requestLayout को ट्रिगर कर सकते हैं।
ConstraintLayout निर्धारित बाधाओं के आधार पर स्वतंत्र रूप से बच्चों के मापन का प्रबंधन करता है। यदि ConstraintLayout के अंदर कोई कस्टम View onMeasure को ओवरराइड करता है, तो उसे ConstraintLayout से भेजे गए MeasureSpec को सही ढंग से संभालना चाहिए, अन्यथा बाधाएँ काम नहीं कर सकती हैं। ConstraintLayout गणना के लिए अपने स्वयं के WidgetContainer के साथ दो-पास एल्गोरिदम का उपयोग करता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें