onLayout(): bu nədir, yerləşdirmə alqoritmi və metod parametrləri

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

onLayout() — bu, valideyn konteynerin koordinat müstəvisində uşaq View-lərin mövqelərini və ölçülərini təyin edən ViewGroup sinfinin metodudur. Android sistemi onLayout-u ölçmə mərhələsindən (onMeasure) sonra, hər bir uşaq View üçn ölçülmüş en və hündürlük artıq məlum olduqda çağırır. Android Developers Documentation (2026)-a görə, onLayout hər hansı fərqli ViewGroup-da yenidən təyin edilməsi məcburi olan metoddur, çünki ViewGroup-un standart tətbiqi uşaqların avtomatik yerləşdirilməsini yerin yetirmir.

Əsas məqamlar

  • onLayout(boolean changed, int l, int t, int r, int b) — valideyn koordinatlarında uşaq elementlərin mövqelərini təyin edən ViewGroup metodu
  • child.layout(l, t, r, b) — hər bir uşaq View üçn onun son sərhədlərini təyin edən çağırış
  • Layout mərhələsi View-in həyat dövründə measure mərhələsindən sonra və draw mərhələsindən əvvəl gəlir
  • getWidth() və getHeight() onMeasure-dən sonra əldə edilən getMeasuredWidth-dən fərqli olaraq, yalnız onLayout yerin yetirildikdən sonra əldə edilir
  • requestLayout() — yerləşdirməyə təsir edən məlumatlar dəyişdirildikdə onMeasure və onLayout-un təkrari çağırılmasına səbəb olan metod

onLayout() nədir?

onLayout(boolean changed, int l, int t, int r, int b) — bu, valideyn konteyner daxilində uşaq View-lərin yerləşdirilməsi üçn sistem tərəfindən çağırılan ViewGroup sinfinin protected metodudur. Tərtibatçı bu metodu qeyri-standart element yerləşdirməsi olan fərqli ViewGroup yaradarkən yenidən təyin edir: kaskad, şəbəkə, dama taxtası və ya ixtiyari koordinatlar üzrə. Hər bir uşaq View child.layout() çağırılaraq öz son sərhədlərini alır.

changed parametri ViewGroup-un öz mövqeyinin və ya ölçüsünün son layout-dan bəri dəyişib-dəyişmədiyini göstərir. changed true olarsa, bütün uşaq elementlər də yəqin ki, yenidən yerləşdirilməli olacaq. l, t, r, b parametrləri ViewGroup-un valideyninin koordinat sistemində yuxarı sol və aşağı sağ künclərinin koordinatlarıdır. onLayout daxilində tərtibatçı bu dəyərləri uşaqları yerləşdirmək üçn başlanğıc koordinatlar kimi istifadə edir.

ViewGroup — onLayout-u yenidən təyin edən yeganə sinifdir. Adi View (ViewGroup deyil) uşaq elementlərə malik deyil və onLayout-a ehtiyac duymur — onun öz yerləşdirilməsi valideyn konteyner tərəfindən idarə olunur. Adi View onLayout-u yenidən təyin etsə belə, sistem onu çağırmayacaq. Bu, hər hansı View üçn çağırılan onMeasure-dən onLayout-un əsas fərqidir.

Layout mərhələsinin icra axını

Layout mərhələsi kök View-də layout(int l, int t, int r, int b) public metodunun çağırılması ilə başlayır. Bu metod View-in öz son koordinatlarını təyin edir və View ViewGroup-dursa, onLayout-u çağırır. Sonra onLayout hər bir uşaq element üçn rekursiv olaraq child.layout() çağırır və proses iyerarxiyada aşağıya doğru davam edir. Beləliklə, layout kökdən yarpaqlara yayılır.

onLayout çağırmazdan əvvəl sistem View-in ölçülərinin əvvəlki dövrə nisbətən dəyişib-dəyişmədiyini yoxlayır. Əgər ölçülər dəyişməyibsə və requestLayout çağırılmayıbsa, onLayout çağırılmaya bilər — sistem əvvəlki layout-un nəticələrindən istifadə edir. Bu, yalnız məzmunun dəyişdiyi, lakin ölçülərin dəyişmədiyi animasiyalar və ya sürüştürmə zamanı lazımsız mövqe yenidən hesablamalarının qarşısını alan optimallaşdırmadır.

requestLayout() — View-in layout-unun köhnəldiyini və yenidən hesablanmasının tələb olunduğunu sistemə bildirən View metodudur. requestLayout çağırılması tam dövrə səbəb olur: əvvəlcə onMeasure, sonra onLayout, daha sonra onDraw çağırılır. Yalnız yenidən çəkməyə başlayan invalidate-dən fərqli olaraq, requestLayout ölçülərin və mövqelərin tam yenidən hesablanmasına başlayır. Həddindən artıq çağırma requestLayout performans problemlərinin ümumi səbəbidir.

onLayout parametrləri: l, t, r, b

l (left) — ViewGroup-un valideyn koordinat sistemində sol kənarının X koordinatı. t (top) — yuxarı kənarın Y koordinatı. r (right) — sağ kənarın X koordinatı. b (bottom) — aşağı kənarın Y koordinatı. ViewGroup-un eni r - l, hündürlüyü isə b - t kimi hesablanır. Bu koordinatlar artıq ViewGroup-un öz padding-lərini əhatə edir.

onLayout daxilində tərtibatçı hər bir uşaq View üçn child.layout(int childLeft, int childTop, int childRight, int childBottom) çağırır. child.layout-ə ötürülən koordinatlar valideyn ViewGroup-un koordinat sistemində olmalıdır. Adətən, childLeft və childTop valideynin padding-ləri nəzərə alınmaqla hesablanır: childLeft = l + paddingLeft + offsetX, childTop = t + paddingTop + offsetY.

Tipik istifadə
ParametrTəsvir
l (left)ViewGroup-un valideyndə sol kənarının koordinatıUşaq elementlər üçn X oxu üzrə başlanğıc nəqtə
t (top)ViewGroup-un valideyndə yuxarı kənarının koordinatıUşaq elementlər üçn Y oxu üzrə başlanğıc nəqtə
r (right)ViewGroup-un valideyndə sağ kənarının koordinatıEnin yuxarı həddi, r - l = getWidth()
b (bottom)ViewGroup-un valideyndə aşağı kənarının koordinatıHündürlüyün yuxarı həddi, b - t = getHeight()

Uşaq elementlər üçn koordinatların hesablanması

Uşaq koordinatları düsturla hesablanır: childLeft = l + paddingLeft + (marginLeft if present), childRight = childLeft + child.getMeasuredWidth(). Şaquli olaraq: childTop = t + paddingTop + (marginTop), childBottom = childTop + child.getMeasuredHeight(). Bu dörd dəyər hesablandıqdan sonra child.layout(childLeft, childTop, childRight, childBottom) çağırılır.

Kotlin-də onLayout ilə fərqli ViewGroup nümunəsi

FlowLayout yaradaq — uşaq View-ləri sətirlərə yerləşdirən, cari sətir dolduqda elementləri yeni sətirə keçirən fərqli ViewGroup. Bu, bir müstəvidə wrap ilə Flexbox-un analoqudur. onLayout bütün uşaq View-ləri dövr edir, hər biri üçn mövqe hesablayır və child.layout() çağırır.

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

onLayout və onMeasure arasındakı fərqlər

onMeasureonLayout — View-in həyat dövrünün ardıcıl iki mərhələsi olub, prinsipial olaraq fərqli vəzifələr yerin yetirir. onMeasure View-in istənilən (measured) ölçülərini təyin edir, onLayout isə faktiki (actual) koordinatları və ölçüləri müəyyən edir. Əsas fərq: onMeasure-də ölçülər müvəqqqeti ola və sonra valideyn tərəfindən düzəldilə bilər, onLayout-da isə hər bir uşaq View-in son mövqeyi müəyyən edilir.

onMeasure hər bir View üçn, o cümlədən yarpaq tipli (TextView, ImageView, Button) çağırılır. onLayout yalnız ViewGroup üçn çağırılır. Bu, yerləşdirmənin View-in özünün deyil, valideyn konteynerin məsuliyyəti olması ilə əlaqəlidir. Yarpaq View öz mövqeyini valideyn onLayout-dan çağırılan layout() vasitəsilə alır.

getMeasuredWidth()getMeasuredHeight() onMeasure-dən sonra, getWidth()getHeight() isə yalnız onLayout-dan sonra əldə edilir. Əgər onMeasure daxilində getWidth()-ə müraciət etsəniz, əvvəlki dövrün dəyəri və ya sıfır qaytarılacaq. Buna görə onMeasure-də ölçüləri hesablamaq üçn MeasureSpec və ardıcıl olaraq children istifadə edilməlidir.

onLayout ilə işləyərkən tipik səhvlər

Padding nəzərə alınmadan yerləşdirmə — onLayout tətbiq edilərkən ilk səhv. Tərtibatçı tez-tez uşaq View-lərin başlanğıc koordinatlarına valideynin paddingLeftpaddingTop dəyərlərini əlavə etməyi unudur. Nəticədə children ViewGroup-un kənarında göstərilir, setPadding() və ya XML-də təyin edilmiş boşluqları nəzərə almır. Düzgün hesablama: childLeft = paddingLeft + offsetX.

Görünməyən uşaqlar üçn layout çağırılması — ikinci geniş yayılmış problem. ViewGroup-un tərkibində visibility-si GONE olan uşaq View-lər varsa, onları yerləşdirməyə ehtiyac yoxdur — onlar yer tutmur. Lakin onLayout bu halı düzgün idarə etməli, GONE uşaqları ötürərək keçməlidir. INVISIBLE uşaqlar üçn layout yenə də çağırılmalıdır — onlar göstərilməsə də, öz yerini qoruyur.

changed parametrinin nəzərə alınmaması — üçüncü səhv. changed parametri ViewGroup-un ölçülərinin və ya mövqeyinin dəyişib-dəyişmədiyini göstərir. Əgər changed == false olarsa, keşlənmiş koordinatlardan istifadə edə və bütün uşaq elementlərin layout-unu yenidən hesablamaya bilərsiniz. Lakin layout-un tam keşlənməsi çətin məsələdir və əksər onLayout tətbiqləri hər dəfə bütün elementləri yenidən hesablayır. Bu, az sayda uşaq olduqda məqbuldur.

Tez-tez verilən suallar

ViewGroup-da onLayout-u yenidən təyin etməmək olarmı?

Olar, əgər ViewGroup standart LayoutParams istifadə edirsə və xüsusi yerləşdirmə məntiqi əlavə etmirsə. Lakin ViewGroup-da onLayout-un standart tətbiqi heç bir şey etmir — uşaq elementlər yerləşdirilməyəcək. Təcrübədə bütün ViewGroup-lar (LinearLayout, RelativeLayout, FrameLayout) onLayout-u yenidən təyin edir.

Layout və onLayout arasındakı fərq nədir?

layout() — sistem və ya valideyn ViewGroup tərəfindən çağırılan View-in public final metodudur. O, View-in öz koordinatlarını təyin edir və View ViewGroup-dursa, onLayout-u çağırır. onLayout() — tərtibatçı tərəfindən uşaq elementlərin xüsusi yerləşdirilməsi üçn yenidən təyin edilən protected metoddur.

onLayout requestLayout-u çağıra bilərmi?

Texniki olaraq — bəli, çağıra bilər. Lakin bu qətiyyənlə tövsiyə edilmir, çünki sonsuz rekursiyaya səbəb olur: requestLayout → onMeasure → onLayout → requestLayout. Əgər onLayout daxilində requestLayout çağırılarsa, sistem StackOverflowError istisnası atacaq. Bütün ölçü dəyişiklikləri onLayout-dan əvvəl yerin yetirilməlidir.

onLayout animasiyalarla necə işləyir?

Layout animasiyaları (LayoutTransition) uşaq View-lərin mövqe dəyişikliklərini ələ keçirir və keçid animasiyası tətbiq edir. LayoutTransition aktiv olduqda, onLayout əvvəlcə son mövqeləri təyin edir, sonra LayoutTransition köhnə mövqedən yenisinə hərəkəti animasiya edir. Bu, düzgün son koordinatlarla onLayout-un düzgün tətbiqini tələb edir.

Niyə onLayout invalidate-dən sonra çağırılmır?

invalidate() yalnız draw mərhələsini (yenidən çəkmə) işə salır, measure və layout-a təsir etmir. onLayout-u işə salmaq üçn requestLayout() çağırılmalıdır, o da tam dövrə başlayır: measure → layout → draw. invalidate ölçülər və mövqelər dəyişmədikdə görünüşü yeniləmək üçn daha səmərəlidir.

Xülasə

  • onLayout() — ölçmə mərhələsi başa çatdıqdan sonra uşaq View-lərin son mövqelərini təyin edən ViewGroup metodu
  • child.layout(l, t, r, b) — hər bir uşaq element üçn koordinatların təyin edilməsinin əsas mexanizmi
  • l, t, r, b parametrləri — ViewGroup-un valideyn sistemində kənar koordinatları, en = r - l, hündürlük = b - t
  • Layout mərhələsi kök View-dən uşaq elementlərə rekursiv yayılır, hər ViewGroup-da onLayout çağırılır
  • requestLayout() yalnız yenidən çəkməyə başlayan invalidate-dən fərqli olaraq, ölçülərin və mövqelərin tam yenidən hesablanmasına başlayır
  • Padding-in nəzərə alınması onLayout-da məcburidir — uşaqların başlanğıc koordinatları valideynin paddingLeft və paddingTop dəyərlərini əhatə etməlidir

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