UIView Auto Layout LifeCycle

Melisa Öztürk
Team Kraken
Published in
4 min readMar 31, 2021

Swift ile uygulama yazarken hepimiz UI’daki bazı düzenlemeler için ‘layoutIfNeeded()’, ‘setNeedsLayout()’ gibi metotları kullanıyoruz. Bazen bir kaç tanesini bir arada kulladığımız da oluyor. Kendim için şunu söyleyebilirim ki bugüne kadar bunları bilinçli olarak kullanmamıştım. Bu nedenle bu metotları sizlerle beraber detaylı olarak inceleyelim istedim.

Başlamadan önce içeriği anlamızda yardımcı olacak bazı temel yapıları inceleyelim.

Main Run Loop

Gelen işlemleri planlayan, yöneten, işleyen bir döngüsel bir yapıdır. Amacı yapılacak işlemler varsa thread‘leri meşgul tutmak, yapılacak işlem yok ise thread‘lerin uyku haline geçmesini sağmaktır. İşlemler yapıldıktan sonra update cycle başlar.

Update Cycle

View ‘lerin konumlandırılması ve çizilmesi sürecinden sorumlu olan yapıdır.

Layout Pass

View‘lere ve subview‘lere ait frame‘leri constraint‘ler yardımı ile hesaplayan yapıdır.

Bounds

View’in parent’ına göre boyutları ve konumu.

Frame

View’in kendi boyutları ve konumu.

Auto Layout nedir ?

Bir iOS uygulamasında, hiyerarşik olarak View ‘lerin boyut ve konumlarını constraint’lere dayanarak hesaplayan yapıdır.

Örneğin; Bir label ’ı bir view içerisine yerleştirip top ve bottom constraint‘ler verdiğiniz. View ‘inizin boyunu arttırınca içerideki label tekrar konumlanır.

Auto Layout döngüsü 3 adımdan oluşur. Update, Layout, Display.

Bir view oluştuktan sonra 3 adımı gerçekleşir. Bu view için herhangi bir adım ya da tüm döngü tekrar edebilir.

1) Update:

Bu kısımda view’e ait frame oluşturulur.

updateConstraints():

‘updateConstraints()’ metodu update adımında devreye girer. Her view için ayrı ayrı çalıştırılır.

UI’daki bazı durumlardan kaynaklı olarak constraint’leri tekrar hesaplatmamız ve update etmemiz gerekebilir. O zaman updateConstraints() metodunun tetiklenebilmesi için ‘setNeedsUpdateConstraints()’ vb metotları kullanabiliriz. Çünkü ‘updateConstraints()’ metodunu tek başına kullanmak işlemsizdir.

NOT: ‘updateConstraints()’ metodu içerisinde setNeedsUpdateConstraints()’ metodunu çağırmak sonsuz döngü oluşmasına neden olabilir.

setNeedsUpdateConstraints():

Var olan constraint’leri geçersiz kılarak bir sonraki update cycle için constraint’lerin update edileceğini garantiler. Her constraint güncelleme işlemi için ‘updateConstraints()’ metodunu tetikler. ‘setNeedsDisplay() ve ‘setNeedsLayout()’ metotları ile benzer görevdedir.

NOT: View’deki herhangi bir constraint’i değiştirdiğimizde ‘setNeedsUpdateConstraints()’ metodunu çağırarak view’e ait constraint’lerin güncellenmesine ihtiyacı olup olmadığını kontrol ederek gerekli güncelemeleri yapabiliriz. Bunun için ‘setNeedsUpdateConstraints()’ metodunu çağırırız ve layout oluşmadan önce sistem ‘updateConstraints()’ metodunu çağırarak constraint’lerimiz günceller.

updateConstraintsIfNeeded():

‘setNeedsUpdateConstraints()’ metodu veya ‘invalidateInstrinsicContentSize’ constraint değişikliği gerekli ise buna göre bir flag oluşturur. ‘updateConstraintsIfNeeded()’ metodu ise bu flag için kontrol gerçekleştirir. Eğer yapılması gereken bir değişiklik var ise ‘updateConstraints()’ metodunu çağırır.

NOT: Bu aşamada constraint güncellemesi yapmak sorunlara neden olabilir.

invalidateIntrinsicContentSize():

View ‘in sahip olduğu intrinsicContentSize‘ı (view ‘e ait boyular) geçersiz kılar. Böylece intrinsicContentSize ‘ın geçersiz olduğunu belirten bir flag atar ve intrinsicContentSize layout pass ’te tekrar hesaplanır.

2) Layout:

UI ‘daki oluşturduğumuz her katman bir layout oluşturur.

http://gph.is/1PGU7OW

layoutSubviews() :

Bir view‘in subview‘i için frame işlemi yapacaksak kullanırız.

Uygulamayı çalıştırdığımızsa UI ‘daki tüm view’ler için hiyerarşik olarak (En üstteki view’den en alttaki view’e doğru) layoutSubviews() metodu çağırılır. Subview için bir frame(boyut ve pozisyon) atamak istersek en uygun yer bu metot olacaktır. Bu metodu view için autoresizing ve constraint davranışları istediğimiz gibi çalışmıyorsa kullanmamız daha doğru bir yaklaşım olacaktır.

Bir view’in bütün subview’leri etkiler. Bu nedenle bu metodu direkt olarak kullanmak yerine bu metodu tetikleyen diğer metotları kullanmak daha performanslı bir kullanım olacaktır.

NOT: ‘layoutSubviews()’ metodunu override ederken ‘setNeedsLayout()’ ya da ‘setNeedsUpdateConstraints()’ metotlarını çağırırsak sonsuz bir döngüye neden olabiliriz.

*** layoutSubviews() metodunun tetiklendiği bazı durumlar:

  • View ‘e bir subview eklenmesi ya da silinmesi
  • Bir subview ’e ait bounds yapısının değişmesi.
  • Scroll view ‘in kaydırılması işlemi

setNeedsLayout():

View’i tekrar çizmek ve tekrar yerleştirmek için ‘layoutSubviews()’ metodunu tetikler. İşlemler gerçekleşir, buna bağlı olarak bir değer döner. View’in bir sonraki update cycle‘da güncelleneceğine dair bir flag atar ve layout bir sonraki update cycle‘da güncellenir.

‘layoutSubviews()’ bir asynchronous(eş zamansız) metottur. İşemler o an tamamlanır ve bir sonuç döner ama biz sonucu bir sonraki döngüde layout tekrar çizildiğide görürüz.

NOT: ‘layoutSubviews()’ metodunu override edersek view’lerın frame’leri ile ilgili veriler alınıp yine üzerinde oynamalar yapabiliriz.

layoutIfNeeded():

View ‘in layout’larını anında güncellemek için kullanabiliriz. Sisteme işlemi anında gerçekleştirmek istediğini söyler ve işlem update cycle‘ı beklemeden gerçekleşir. ‘layoutIfNeeded()’ synchronous(eş zamanlı) çalışan bir metottur.

3) Display:

Bu adımda ekranda görünmesini istediğimiz view vb. elemanların çizim işlemleri gerçekleşir. Çizim işlemi parent view’den subview’e doğru gerçekleşir.

AutoLayout’un enable ya da disable olmasından bağımsız olarak çalışır.

draw(_:):

Gelen veriyi ekranda görebilmemiz için çizim işlemlerinin gerçekleşmesini sağlayan yapıdır. ’layoutSubviews()’ metodu ile benzerlik gösterir. Ama subview’ler için gelen sonraki draw isteklerini tetiklemez. Yine bu metodu da direkt çağırmamamız, bunu yerine bu metodu tetikleyici metot ya da yapılardan yararlanmamız gerekir.

Parametre olarak ‘rectangle’ alır. Rectangle view’imizin temel iskelet yapısını belirtir.

setNeedsDisplay():

’setNeedsLayout()’ metodu ile benzer özeliktedir. Herhangi bir içerik güncellemesi olduğunda bir flag ataması yapar. View tekrar çizilmeden önce değer döner. Bir sonraki update cycle‘da flag kontrolü yapılır ve ‘draw()’ metodu çalıştırılır.

NOT: Bir view’in her update cycle‘da tekrar çizilmesini istersek ‘setNeedsDisplay()’ metodunu ‘didSet()’ içerisinde çağırmamız yeterlidir.

Update Cycle Summary — credit: https://pin.it/2Yhft8A

Daha detaylı bilgi için: https://developer.apple.com/documentation/uikit/uiview

Yazılarımızın devamı için TeamKraken ‘i takip etmeyi unutmayın. Desteklerinizi bekliyoruz.

--

--