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) — 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ə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.
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.
| Parametr | Təsvir | Tipik istifadə|
|---|---|---|
| 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 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.
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.
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)
}
onMeasure və onLayout — 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() və getMeasuredHeight() onMeasure-dən sonra, getWidth() və 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.
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 paddingLeft və paddingTop 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
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() — 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.
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.
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.
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ə
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.
Həm də oxuyun