onMeasure(): bu nədir, MeasureSpec rejimləri və metodun yenidən təyin edilməsi

Müəllif: IT Sectr Dərc olunub: 2026-07-22 Oxuma vaxtı: 9 dəq

onMeasure() — android.view.View sinfinin qorunan metodudur və sistem Android tərəfindən View-in ölçülərini təyin etmək üçün çağırılır. Sistem metoda iki MeasureSpec obyekti ötürür, onların hər biri ölçmə rejimini (EXACTLY, AT_MOST və ya UNSPECIFIED) və valideyn konteyner tərəfindən təklif olunan ölçünü ehtiva edir. Android Developers Documentation (2026) məlumatına görə, MeasureSpec-in düzgün işlənməsi ilə onMeasure-in yenidən təyin edilməsi ölçülər üzərində dəqiq nəzarət tələb edən bütün xüsusi View və ViewGroup-lar üçün məcburi mərhələdir.

Əsas məqamlar

  • onMeasure(int widthMeasureSpec, int heightMeasureSpec) — valideyndən MeasureSpec-in ötürülməsi ilə ölçüləri ölçmək üçün View metodu
  • MeasureSpec — ölçmə rejimini (UNSPECIFIED, EXACTLY, AT_MOST) və ölçünü kodlayan 32-bitlik dəyər
  • setMeasuredDimension(int w, int h) — onMeasure daxilində məcburi çağırış, View-in yekun ölçülərini təsbit edir
  • İkiprokedli alqoritm ölçmə: valideyn uşaqları ölçür, sonra uşaqlar öz ölçülərini bildirir və valideyn qəti qərar verir
  • measureChildWithMargins — xüsusi ViewGroup-larda uşaq View-ləri ölçmək üçün köməkçi metod

onMeasure() nədir?

onMeasure(int widthMeasureSpec, int heightMeasureSpec) — View sinfinin metodudur, sistem Android tərəfindən görünüşün enini və hündürlüyünü təyin etmək üçün çağırılır. Tərtibatçı bu metodu yenidən təyin edərək, MeasureSpec-də ötürülən məhdudiyyətlər əsasında View-in hansı ölçüdə olması lazım olduğunu göstərir. onMeasure-in düzgün yenidən təyin edilməsi olmadan xüsusi View səhv göstərilə bilər və ya ümumiyyətlə göstərilməyə bilər.

Sistem onMeasure-i View-in həyat dövrünün measure mərhələsində çağırır, bu mərhələ layout (onLayout) və draw (onDraw) mərhələlərindən əvvəl gəlir. Əgər View onMeasure-i yenidən təyin etmirsə, background drawable və ya layout_params əsasında standart ölçüləri təyin edən superklassın implementasiyası istifadə olunur. super.onMeasure(widthMeasureSpec, heightMeasureSpec) çağırışı yalnız TextView və ya ImageView kimi standart View alt sinifləri üçün işləyir.

onMeasure üçün əsas tələb setMeasuredDimension(int, int) çağırışının metodun sonunda mütləq mövcud olmasıdır. Əgər bu çağırış yoxdursa, sistem View-in ölçülmüş ölçüləri təsbit etmədiyi barədə mesajla IllegalStateException istisnası yaradır. Yekun ölçülər measure mərhələsi başa çatdıqdan sonra getMeasuredWidth()getMeasuredHeight() getter-ləri vasitəsilə əlçatan olur.

MeasureSpec rejimləri: üç əsas dəyər

MeasureSpec — 32-bitlik tam ədəddir, burada yuxarı 2 bit ölçmə rejimini, aşağı 30 bit isə ölçünü kodlayır. Rejim View-in öz ölçüsünü seçməkdə nə dərəcədə sərbəst olduğunu müəyyən edir. Android üç rejim təqdim edir: EXACTLY, AT_MOST və UNSPECIFIED. Hər bir rejim onMeasure-də fərqli emal məntiqini diktə edir.

MeasureSpec rejimiDəyərDavranış
EXACTLYValideyn dəqiq ölçünü təyin etdiView sərhədləri aşmaq istəmirsə, ötürülən ölçüyə tam uyğunlaşmalıdır
AT_MOSTValideyn maksimum ölçünü təyin etdiView 0-dan ötürülən maksimuma qədər istənilən ölçünü seçə bilər
UNSPECIFIEDValideyn məhdudiyyət qoymurView yuxarı məhdudiyyət olmadan istənilən arzu olunan ölçünü seçə bilər

MeasureSpec-dən rejim və ölçünü çıxarmaq üçün MeasureSpec sinfinin statik metodları istifadə olunur: MeasureSpec.getMode(int) üç rejimdən birini qaytarır (EXACTLY, AT_MOST, UNSPECIFIED), MeasureSpec.getSize(int) isə pikseldə rəqəmsal ölçünü qaytarır. Öz MeasureSpec-inizi yaratmaq üçün MeasureSpec.makeMeasureSpec(int size, int mode) istifadə olunur. Bu üç metod onMeasure-də ölçülərlə işin bütün ssenarilərini əhatə edir.

MeasureSpec-in emalı üçün tipik məntiq

Standart nümunə MeasureSpec emalı: əgər rejim EXACTLY-dirsə — ötürülən ölçünü yekun olaraq istifadə edin; əgər AT_MOST-dursa — arzu olunan ölçüdən (View-in məzmunu) və ötürülən maksimumdan minimumu seçin; əgər UNSPECIFIED-dirsə — məhdudiyyət olmadan View-in arzu olunan ölçüsünü istifadə edin. Bu nümunə valideynin istənilən məhdudiyyətlərində düzgün davranışı təmin edir.

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 istifadəsi

Standart məntiqi sadələşdirmək üçün Android resolveSizeAndState metodunu təqdim edir, bu metod arzu olunan ölçünü, MeasureSpec-i qəbul edir və düzgün rejimlə yekun ölçünü qaytarır. Bu metod yuxarıda təsvir olunan nümunəni bir sətir kodda həyata keçirir. Həmçinin resolveSize(int size, int measureSpec) funksiyası mövcuddur, dövlət bitləri olmadan təmiz ölçünü qaytarır.

İkiprokedli ölçmə alqoritmi

Android iki prokedli ölçmə alqoritmindən (two-pass measure) istifadə edir ki, bu da iyerarxiyada hər bir View-in valideyn məhdudiyyətləri və uşaq elementlərinin üstünlükləri nəzərə alınmaqla düzgün ölçülər almasını təmin edir. Birinci prokeddə valideyn uşaq View-lərə məhdudiyyətlərlə MeasureSpec ötürür, uşaq View-lər isə öz arzu olunan ölçülərini hesablayır. İkinci prokeddə valideyn ölçülər haqqında qəti qərar verir.

ViewGroup üçün ölçmə prosesi daha mürəkkəbdir: valideyn əvvəlcə bütün uşaq elementlərini ölçməli, sonra onların ölçüləri əsasında öz ölçüsünü təyin etməlidir. measureChildren(int widthMeasureSpec, int heightMeasureSpec) çağırışı bütün uşaq View-lər arasında dövr edir və hər biri üçün measure(child, childWidthSpec, childHeightSpec) çağırır. Bütün uşaq elementləri ölçüldükdən sonra ViewGroup öz ölçüləri ilə setMeasuredDimension çağırır.

Əhəmiyyətli nüans: measure metodu (public, final) yenidən təyin edilə bilməz — onun əvəzinə onMeasure yenidən təyin edilir. Bu, sistemin onMeasure çağırışından əvvəl və sonra xidməti hərəkətləri yerinə yetirə bilməsini təmin edir, məsələn, ölçü dəyişikliyini yoxlamaq və sonrakı çəkmə üçün çirkli sahəni hesablamaq. Əgər View sabit ölçülərə malikdirsə, onMeasure-in yenidən təyin edilməsi tələb olunmaya bilər.

MEASURED_SIZE_STATE bayrağı

MeasureSpec təkcə ölçü və rejimi deyil, həm də MeasureSpec.getMode() vasitəsilə əldə edilə bilən dövlət bitlərini (state bits) ehtiva edir. setMeasuredDimension çağırışından sonra dövlət View-in ölçülmüş ölçülərinin bir hissəsinə çevrilir və getMeasuredState() vasitəsilə yoxlanıla bilər. Bu, ScrollView və digər sürüşdürülə bilən konteynerlərdə uşaqlara məhdudiyyətlərin düzgün ötürülməsi üçün istifadə olunur.

Kotlin-də onMeasure-in yenidən təyin edilməsi nümunəsi

Praktiki nümunəni nəzərdən keçirək — kvadrat göstərmək üçün onMeasure-in yenidən təyin edilməsi ilə xüsusi View yaradılması. SquareView sinfi View-dən miras alır və ötürülən MeasureSpec-lərdən asılı olmayaraq en və hündürlüyün həmişə bərabər olmasını təmin edir. onMeasure-də kiçik tərəf müəyyən edilir və kvadrat ölçü təyin olunur.

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

Uşaq elementlərinin ölçülməsi ilə xüsusi ViewGroup

ViewGroup daha mürəkkəb onMeasure məntiqi tələb edir, çünki əvvəlcə uşaq elementləri ölçülür, sonra ViewGroup-un öz ölçüsü müəyyən edilir. CascadeLayout nümunəsi uşaq elementlərini fasilə ilə kaskad şəklində yerləşdirir. measureChildWithMargins vasitəsilə bütün uşaq elementləri ölçüldükdən sonra ümumi en və hündürlük hesablanır.

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

onMeasure-in yenidən təyin edilməsində tipik səhvlər

setMeasuredDimension çağırışının buraxılması — ən çox yayılmış səhvdir. Əgər tərtibatçı onMeasure-i yenidən təyin edib, lakin setMeasuredDimension çağırmayıbsa, tətbiq IllegalStateException ilə çökəcək. Bu xüsusilə metoddə şərtli budaqlanmalar olduqda və budaqlardan birində çağırış olmadıqda tez-tez baş verir. onMeasure-də kodun hər bir budağı setMeasuredDimension çağırışı ilə bitməlidir.

AT_MOST rejiminə məhəl qoymamaq — ikinci ən çox rast gəlinən səhvdir. Əgər View AT_MOST rejimində məzmuna görə hesablama əvəzinə həmişə ötürülən ölçüdən istifadə edirsə, valideyn konteyner məkanı düzgün bölüşdürə bilməyəcək. Məsələn, AT_MOST-da TextView mətnin enini hesablamalı və arzu olunan və ötürülən endən minimumu istifadə etməlidir. AT_MOST-a məhəl qoymamaq View-in kiçik məzmunda belə bütün mövcud məkanı tutmasına səbəb olur.

onMeasure daxilində obyektlərin yaradılması — klassik performans səhvdir. onMeasure dəfələrlə çağrıla bildiyindən (hər layout tələbində), bu metod daxilində obyektlərin (Paint, Rect, String) yaradılması yaddaşı zibilləyir və zibil toplayıcısını təhrik edir. Bütün obyektlər View-in konstruktorunda bir dəfə yaradılmalı, onMeasure-də isə yalnız ölçülərin hesablanması məntiqi yerinə yetirilməlidir. Eyni qayda onDraw və onLayout üçün də keçərlidir.

ViewGroup-da uşaq View-lərin ölçülməsi

measureChildWithMargins — ViewGroup-un qorunan metodudur, bir uşaq View-i onun MarginLayoutParams nəzərə alınmaqla ölçür. Metod valideynin MeasureSpec-ini və en və hündürlük üzrə yığılmış yerdəyişmələri qəbul edir. Avtomatik olaraq uşaq View üçün MeasureSpec-i düzəldir, valideynin padding-lərini və uşağın margin-lərini çıxarır və düzəldilmiş MeasureSpec-i child.measure()-a ötürür.

Qabaqcıl ölçmə məntiqi üçün ViewGroup measureChild(View child, int parentWidthSpec, int parentHeightSpec)-i yenidən təyin edə və ya hər bir uşaq elementi üçün birbaşa MeasureSpec ilə işləyə bilər. Məsələn, LinearLayout onMeasure-də bütün uşaq View-lər arasında dövr edir, hər birini onun layout_weight nəzərə alınmaqla ölçür və qalan məkanı proporsional olaraq bölüşdürür. Bu yanaşma ixtiyari düzülüş alqoritmlərini həyata keçirməyə imkan verir.

Ölçmə nəticələrinin ölçü keşi (measure cache) mexanizmi vasitəsilə keşləşdirilməsi müəyyən ViewGroup-larda setMeasureWithLargestChildEnabled bayrağı vasitəsilə mövcuddur. Lakin əksər hallarda onMeasure hər hansı layout dəyişikliyində təkrar çağırılır və keşləşdirmə tətbiq edilmir. Xüsusi ViewGroup-larda keşə güvənmək əvəzinə onMeasure-də hesablamaları minimuma endirmək tövsiyə olunur.

Tez-tez verilən suallar

Xüsusi View üçün onMeasure-i yenidən təyin etmək məcburidirmi?

Bəli, əgər xüsusi View birbaşa View sinfindən miras alırsa. Əgər miras TextView, ImageView və ya Button-dan onların standart ölçüləri ilə gedirsə, onMeasure-i yenidən təyin etmək lazım deyil. ViewGroup üçün onMeasure-in yenidən təyin edilməsi həmişə tələb olunur — əks halda uşaq elementləri düzgün ölçülməyəcək.

setMeasuredDimension çağırılmasa nə baş verir?

Android sistemi IllegalStateException istisnası atır, mətni: “The View did not call setMeasuredDimension”. Bu istisna onMeasure başa çatdıqdan sonra measure() metodunda, yekun ölçülər sıfır qaldıqda yaranır. İstisna try-catch ilə işlənməzsə, tətbiq çökür.

getWidth getMeasuredWidth-dən nə ilə fərqlənir?

getMeasuredWidth() onMeasure-də təyin edilmiş ölçünü qaytarır (ölçmə mərhələsi). getWidth() View-in onLayout-da bütün mövqe düzəlişləri nəzərə alındıqdan sonra aldığı faktiki ölçünü qaytarır. Əksər View-lər üçün bu dəyərlər üst-üstə düşür, lakin xüsusi ViewGroup-larda fərqlənə bilər.

onMeasure-də animasiyaları və ya View-in vəziyyətini dəyişmək olarmı?

Xeyr, onMeasure yalnız ölçülərin hesablanması üçün nəzərdə tutulub. Bu metoddə vəziyyətin dəyişdirilməsi, animasiyaların işə salınması, şəbəkə ilə işləmə və ya məlumatların yenilənməsi Android arxitekturasını pozur və rekursiv measure çağırışlarına səbəb ola bilər, çünki vəziyyətin dəyişməsi requestLayout-u tetikleyə bilər.

onMeasure ConstraintLayout ilə necə qarşılıqlı təsir göstərir?

ConstraintLayout verilmiş məhdudiyyətlər əsasında uşaq elementlərinin ölçülməsini müstəqil idarə edir. Əgər ConstraintLayout daxilində xüsusi View onMeasure-i yenidən təyin edirsə, ConstraintLayout-dan ötürülən MeasureSpec-i düzgün emal etməlidir, əks halda məhdudiyyətlər işləməyə bilər. ConstraintLayout hesablama üçün öz WidgetContainer ilə iki prokedli alqoritmdən istifadə edir.

Xülasə

  • onMeasure() — Android sistemi tərəfindən measure mərhələsində çağırılan, ölçüləri təyin etmək üçün View metodu
  • MeasureSpec ölçmə rejimini (EXACTLY, AT_MOST, UNSPECIFIED) və valideyndən ötürülən ölçünü kodlayır
  • setMeasuredDimension — onMeasure sonunda məcburi çağırış, yekun ölçüləri təsbit edir
  • resolveSize — MeasureSpec-in standart emal məntiqini bir sətirdə həyata keçirən köməkçi metod
  • İkiprokedli alqoritm valideyn-uşaq elementləri iyerarxiyasında düzgün ölçməni təmin edir
  • measureChildWithMargins fasilələr nəzərə alınmaqla xüsusi ViewGroup-larda uşaq View-lərin ölçülməsi üçün istifadə olunur
  • GC riski və kadr gecikmələri səbəbindən onMeasure daxilində obyektlərin yaradılması qətiyyən tövsiyə edilmir

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun