onMeasure() — bu android.view.View sinfining protected metodi bo'lib, Android tizimi tomonidan View o'lchamlarini aniqlash uchun chaqiriladi. Tizim metodga ikkita MeasureSpec obyektini uzatadi, ularning har biri o'lchash rejimini (EXACTLY, AT_MOST yoki UNSPECIFIED) va ota konteyner tomonidan taklif qilingan o'lchamni o'z ichiga oladi. Android Developers Documentation (2026) ma'lumotlariga ko'ra, MeasureSpecni to'g'ri qayta ishlash bilan onMeasureni qayta belgilash o'lchamlar ustida aniq nazorat talab qiladigan barcha maxsus View va ViewGroup'lar uchun majburiy bosqichdir.
Asosiy ma'lumotlar
onMeasure(int widthMeasureSpec, int heightMeasureSpec) — bu View sinfining metodi bo'lib, Android tizimi tomonidan ko'rinishning kengligi va balandligini aniqlash uchun chaqiriladi. Dasturchi ushbu metodni qayta belgilab, MeasureSpec'da uzatilgan cheklovlar asosida View qanday o'lchamda bo'lishi kerakligini ko'rsatadi. onMeasureni to'g'ri qayta belgilamasdan, maxsus View noto'g'ri ko'rsatilishi yoki umuman ko'rsatilmasligi mumkin.
Tizim onMeasure'ni View hayot aylanishining measure bosqichida chaqiradi, bu bosqich layout (onLayout) va draw (onDraw) bosqichlaridan oldin keladi. Agar View onMeasure'ni qayta belgilamasa, background drawable yoki layout_params asosida standart o'lchamlarni o'rnatadigan superklass implementatsiyasi ishlatiladi. super.onMeasure(widthMeasureSpec, heightMeasureSpec) chaqiruvi faqat TextView yoki ImageView kabi standart View pastki sinflari uchun ishlaydi.
onMeasure uchun asosiy talab — setMeasuredDimension(int, int) chaqiruvi metodning oxirida majburiy bo'lishi kerak. Agar bu chaqiruv bo'lmasa, tizim View o'lchangan o'lchamlarni belgilamagani haqida xabar bilan IllegalStateException istisnosini yaratadi. Yakuniy o'lchamlar measure bosqichi tugagandan so'ng getMeasuredWidth() va getMeasuredHeight() getterlari orqali mavjud bo'ladi.
MeasureSpec — bu 32-bitli butun son bo'lib, unda yuqori 2 bit o'lchash rejimini, pastki 30 bit esa o'lchamni kodlaydi. Rejim View o'z o'lchamini tanlashda qanchalik erkin ekanligini aniqlaydi. Android uchta rejimni taqdim etadi: EXACTLY, AT_MOST va UNSPECIFIED. Har bir rejim onMeasure'da turli xil qayta ishlash mantig'ini belgilaydi.
| MeasureSpec rejimi | Qiymat | Xatti-harakat |
|---|---|---|
| EXACTLY | Ota aniq o'lchamni belgiladi | View chegaralardan chiqib ketishni xohlamasa, uzatilgan o'lchamga to'liq mos kelishi kerak |
| AT_MOST | Ota maksimal o'lchamni belgiladi | View 0 dan uzatilgan maksimalgacha istalgan o'lchamni tanlashi mumkin |
| UNSPECIFIED | Ota hech qanday cheklov qo'ymaydi | View yuqori cheklovlarsiz istalgan kerakli o'lchamni tanlashi mumkin |
MeasureSpec'dan rejim va o'lchamni olish uchun MeasureSpec sinfining statik metodlari ishlatiladi: MeasureSpec.getMode(int) uchta rejimdan birini qaytaradi (EXACTLY, AT_MOST, UNSPECIFIED), MeasureSpec.getSize(int) esa pikseldagi raqamli o'lchamni qaytaradi. O'z MeasureSpec'ingizni yaratish uchun MeasureSpec.makeMeasureSpec(int size, int mode) ishlatiladi. Ushbu uchta metod onMeasure'da o'lchamlar bilan ishlashning barcha stsenariylarini qamrab oladi.
Standart namuna MeasureSpecni qayta ishlash: agar rejim EXACTLY bo'lsa — uzatilgan o'lchamni yakuniy sifatida ishlating; agar AT_MOST bo'lsa — kerakli o'lchamdan (View tarkibi) va uzatilgan maksimaldan minimalni tanlang; agar UNSPECIFIED bo'lsa — cheklovlarsiz Viewning kerakli o'lchamidan foydalaning. Ushbu namuna otaning istalgan cheklovlarida to'g'ri xatti-harakatni kafolatlaydi.
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)
}
Standart mantiqni soddalashtirish uchun Android resolveSizeAndState metodini taqdim etadi, u kerakli o'lchamni, MeasureSpecni qabul qiladi va to'g'ri rejim bilan yakuniy o'lchamni qaytaradi. Ushbu metod yuqorida tasvirlangan namunani bir qator kodda amalga oshiradi. Shuningdek, resolveSize(int size, int measureSpec) funksiyasi mavjud bo'lib, u state-bitlarisiz toza o'lchamni qaytaradi.
Android ikki o'tishli o'lchash algoritmidan (two-pass measure) foydalanadi, bu ierarxiyadagi har bir View ota cheklovlari va bola elementlarning afzalliklarini hisobga olgan holda to'g'ri o'lchamlarni olishini kafolatlaydi. Birinchi o'tishda ota bola Viewlarga cheklovlar bilan MeasureSpec uzatadi, bola Viewlar esa o'z kerakli o'lchamlarini hisoblaydi. Ikkinchi o'tishda ota o'lchamlar haqida yakuniy qaror qabul qiladi.
ViewGroup uchun o'lchash jarayoni murakkabroq: ota avval barcha bola elementlarini o'lchashi kerak, so'ngra ularning o'lchamlari asosida o'z o'lchamini aniqlashi kerak. measureChildren(int widthMeasureSpec, int heightMeasureSpec) chaqiruvi barcha bola Viewlar orqali o'tadi va har biri uchun measure(child, childWidthSpec, childHeightSpec) ni chaqiradi. Barcha bola elementlari o'lchangandan so'ng, ViewGroup o'z o'lchamlari bilan setMeasuredDimension ni chaqiradi.
Muhim nuansa: measure metodi (public, final) qayta belgilanishi mumkin emas — uning o'rniga onMeasure qayta belgilanadi. Bu tizim onMeasure chaqiruvidan oldin va keyin xizmat ko'rsatish harakatlarini bajarishini kafolatlaydi, masalan, o'lcham o'zgarishini tekshirish va keyingi chizish uchun iflos maydonni hisoblash. Agar View o'zgarmas o'lchamlarga ega bo'lsa, onMeasureni qayta belgilash talab qilinmasligi mumkin.
MeasureSpec nafaqat o'lcham va rejimni, balki MeasureSpec.getMode() orqali mavjud bo'lgan holat bitlarini (state bits) ham o'z ichiga oladi. setMeasuredDimension chaqiruvidan so'ng, holat Viewning o'lchangan o'lchamlarining bir qismiga aylanadi va getMeasuredState() orqali tekshirilishi mumkin. Bu ScrollView va boshqa aylanma konteynerlarda bolalarga cheklovlarni to'g'ri uzatish uchun ishlatiladi.
Amaliy misolni ko'rib chiqamiz — kvadrat ko'rinish uchun onMeasureni qayta belgilash bilan maxsus View yaratish. SquareView sinfi View' dan meros oladi va uzatilgan MeasureSpec'lardan qat'iy nazar kenglik va balandlik har doim teng bo'lishini kafolatlaydi. onMeasure'da kichik tomon aniqlanadi va kvadrat o'lcham o'rnatiladi.
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 murakkabroq onMeasure mantig'ini talab qiladi, chunki avval bola elementlari o'lchanadi, so'ngra ViewGroup'ning o'z o'lchami aniqlanadi. CascadeLayout namunasi bola elementlarini oraliq bilan kaskad shaklida joylashtiradi. measureChildWithMargins orqali barcha bola elementlari o'lchangandan so'ng, umumiy kenglik va balandlik hisoblanadi.
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 chaqiruvini o'tkazib yuborish — eng keng tarqalgan xato. Agar dasturchi onMeasure'ni qayta belgilagan bo'lsa, lekin setMeasuredDimension'ni chaqirmagan bo'lsa, ilova IllegalStateException bilan ishdan chiqadi. Bu, ayniqsa, metodda shartli tarmoqlanishlar mavjud bo'lganda va tarmoqlardan birida chaqiruv bo'lmaganda tez-tez sodir bo'ladi. onMeasure'dagi kodning har bir tarmog'i setMeasuredDimension chaqiruvi bilan tugashi kerak.
AT_MOST rejimini e'tiborsiz qoldirish — ikkinchi eng keng tarqalgan xato. Agar View AT_MOST rejimida mazmun bo'yicha hisoblash o'rniga har doim uzatilgan o'lchamdan foydalansa, ota konteyner bo'shliqni to'g'ri taqsimlay olmaydi. Masalan, AT_MOST'dagi TextView matn kengligini hisoblashi va kerakli va uzatilgan kenglikdan minimalni ishlatishi kerak. AT_MOST'ni e'tiborsiz qoldirish Viewning kichik mazmunda ham barcha mavjud bo'shliqni egallashiga olib keladi.
onMeasure ichida obyektlarni yaratish — klassik ishlash xatosi. onMeasure ko'p marta chaqirilishi mumkinligi sababli (har bir layout so'rovida), ushbu metod ichida obyektlarni (Paint, Rect, String) yaratish xotirani ifloslantiradi va axlat yig'uvchini qo'zg'atadi. Barcha obyektlar View konstruktorida bir marta yaratilishi kerak, onMeasure'da esa faqat o'lchamlarni hisoblash mantig'i bajarilishi kerak. Xuddi shu qoida onDraw va onLayout uchun ham amal qiladi.
measureChildWithMargins — ViewGroup'ning himoyalangan metodi bo'lib, bitta bola View'ni uning MarginLayoutParams'larini hisobga olgan holda o'lchaydi. Metod otaning MeasureSpec'ini va kenglik va balandlik bo'yicha to'plangan siljishlarni qabul qiladi. Avtomatik ravishda bola View uchun MeasureSpec'ni tuzatadi, otaning padding'larini va bolaning margin'larini ayiradi va tuzatilgan MeasureSpec'ni child.measure() ga uzatadi.
Ilg'or o'lchash mantig'i uchun ViewGroup measureChild(View child, int parentWidthSpec, int parentHeightSpec) ni qayta belgilashi yoki har bir bola elementi uchun to'g'ridan-to'g'ri MeasureSpec bilan ishlashi mumkin. Masalan, LinearLayout onMeasure'da barcha bola Viewlar orqali o'tadi, har birini uning layout_weight'ini hisobga olgan holda o'lchaydi va qolgan bo'shliqni proporsional taqsimlaydi. Ushbu yondashuv ixtiyoriy layout algoritmlarini amalga oshirishga imkon beradi.
O'lchash natijalarini o'lchov keshi (measure cache) mexanizmi orqali keshlash ba'zi ViewGroup'larda setMeasureWithLargestChildEnabled bayrog'i orqali mavjud. Biroq, ko'p hollarda onMeasure har qanday layout o'zgarishida qayta chaqiriladi va keshlash qo'llanilmaydi. Maxsus ViewGroup'larda keshga tayanish o'rniga onMeasure'da hisob-kitoblarni minimallashtirish tavsiya etiladi.
Tez-tez beriladigan savollar
Ha, agar maxsus View to'g'ridan-to'g'ri View sinfidan meros olsa. Agar meros TextView, ImageView yoki Button'dan ularning standart o'lchamlari bilan bo'lsa, onMeasure'ni qayta belgilash shart emas. ViewGroup uchun onMeasure'ni qayta belgilash har doim talab qilinadi — aks holda bola elementlari to'g'ri o'lchanmaydi.
Android tizimi IllegalStateException istisnosini tashlaydi, matni: “The View did not call setMeasuredDimension”. Bu istisno onMeasure tugagandan so'ng measure() metodida, yakuniy o'lchamlar nol bo'lib qolganda yuzaga keladi. Istisno try-catch orqali ishlanmasa, ilova ishdan chiqadi.
getMeasuredWidth() onMeasure'da o'rnatilgan o'lchamni qaytaradi (o'lchash bosqichi). getWidth() View onLayout'da barcha joylashish tuzatishlari hisobga olingandan so'ng olgan haqiqiy o'lchamni qaytaradi. Ko'pchilik Viewlar uchun bu qiymatlar bir xil, ammo maxsus ViewGroup'larda farq qilishi mumkin.
Yo'q, onMeasure faqat o'lchamlarni hisoblash uchun mo'ljallangan. Ushbu metodda holatni o'zgartirish, animatsiyalarni ishga tushirish, tarmoq bilan ishlash yoki ma'lumotlarni yangilash Android arxitekturasini buzadi va rekursiv measure chaqiruvlariga olib kelishi mumkin, chunki holatning o'zgarishi requestLayout'ni tetiklashi mumkin.
ConstraintLayout berilgan cheklovlar asosida bola elementlarini o'lchashni mustaqil boshqaradi. Agar ConstraintLayout ichidagi maxsus View onMeasure'ni qayta belgilasa, ConstraintLayout'dan uzatilgan MeasureSpec'ni to'g'ri qayta ishlashi kerak, aks holda cheklovlar ishlamasligi mumkin. ConstraintLayout hisoblash uchun o'zining WidgetContainer'i bilan ikki o'tishli algoritmdan foydalanadi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.