onMeasure(): bu nima, MeasureSpec rejimlari va metodni qayta belgilash

Muallif: IT Sectr Nashr etilgan: 2026-07-22 O'qish vaqti: 9 daq

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) — otadan MeasureSpecni uzatish bilan o'lchamlarni o'lchash uchun View metodi
  • MeasureSpec — o'lchash rejimini (UNSPECIFIED, EXACTLY, AT_MOST) va o'lchamni kodlovchi 32-bitli qiymat
  • setMeasuredDimension(int w, int h) — onMeasure ichida majburiy chaqiruv, Viewning yakuniy o'lchamlarini belgilaydi
  • Ikki o'tishli algoritm o'lchash: ota bolalarni o'lchaydi, so'ngra bolalar o'z o'lchamlarini bildiradi va ota yakuniy qarorni qabul qiladi
  • measureChildWithMargins — maxsus ViewGroup'larda bola Viewlarni o'lchash uchun yordamchi metod

onMeasure() nima?

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 rejimlari: uchta asosiy qiymat

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 rejimiQiymatXatti-harakat
EXACTLYOta aniq o'lchamni belgiladiView chegaralardan chiqib ketishni xohlamasa, uzatilgan o'lchamga to'liq mos kelishi kerak
AT_MOSTOta maksimal o'lchamni belgiladiView 0 dan uzatilgan maksimalgacha istalgan o'lchamni tanlashi mumkin
UNSPECIFIEDOta hech qanday cheklov qo'ymaydiView 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.

MeasureSpecni qayta ishlashning odatiy mantig'i

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.

kotlin
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)
}

resolveSize dan foydalanish

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.

Ikki o'tishli o'lchash algoritmi

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.

MEASURED_SIZE_STATE bayrog'i

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.

Kotlinda onMeasureni qayta belgilash namunasi

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.

kotlin
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)
    }
}

Bola elementlarni o'lchash bilan maxsus ViewGroup

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.

kotlin
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
        }
    }
}

onMeasureni qayta belgilashda odatiy xatolar

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.

ViewGroup'da bola Viewlarni o'lchash

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

Maxsus View uchun onMeasure'ni qayta belgilash majburiymi?

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.

setMeasuredDimension chaqirilmasa nima bo'ladi?

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.

getWidth getMeasuredWidth'dan nimasi bilan farq qiladi?

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.

onMeasure'da animatsiyalar yoki View holatini o'zgartirish mumkinmi?

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.

onMeasure ConstraintLayout bilan qanday o'zaro ta'sir qiladi?

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

  • onMeasure() — Android tizimi tomonidan measure bosqichida chaqiriladigan, o'lchamlarni aniqlash uchun View metodi
  • MeasureSpec o'lchash rejimini (EXACTLY, AT_MOST, UNSPECIFIED) va otadan uzatilgan o'lchamni kodlaydi
  • setMeasuredDimension — onMeasure oxirida majburiy chaqiruv, yakuniy o'lchamlarni belgilaydi
  • resolveSize — MeasureSpecni qayta ishlashning standart mantig'ini bir qatorda amalga oshiradigan yordamchi metod
  • Ikki o'tishli algoritm ota-bola elementlari ierarxiyasida to'g'ri o'lchashni kafolatlaydi
  • measureChildWithMargins oraliqlarni hisobga olgan holda maxsus ViewGroup'larda bola Viewlarni o'lchash uchun ishlatiladi
  • GC xavfi va kadr kechikishlari sababli onMeasure ichida obyektlarni yaratish qat'iyan tavsiya etilmaydi

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.

Loyihani muhokama qilish

Shuningdek o'qing