Stack View — Hugging ve Compression Resistance Priority Kullanımı

Yunus Tek
NSIstanbul
Published in
6 min readDec 4, 2018

Merhaba, Bu yazıda Compression Resistance ve Hugging priority konusunu ele alıyoruz. Tüm cihazlarda tekil görünümü yaratmak söylendiği kadar zor mu? Cevabı birlikte inceledikten sonra siz verin. Hadi başlayalım.

Stack View Nedir?

Autolayout oluşturmada zorlandığımız noktalarda hızlı çözüm sağlayan StackView iOS 9 ile hayatımıza girdi.

Sağ tarafta gösterilen Stack View’in property’lerinin içindeki objeleri nasıl etkilediklerine şöyle değineyim:

1) Axis

Yatay veya dikey olarak hizalama yapmanızı sağlar:

2) Alignment

Axis durumuna göre aşağıdaki şekillerde hizalama yapmanızı sağlar;
Axis Vertical durumu için: Leading, Training, Fill ve Center
Axis Horizontal durumu için: Top, Buttom, Fill ve Center

3) Distribution

Aşağıdaki kuralları belirleyerek boyut dağılımını yapmanızı sağlar:

Fill: Yeni bir UIStackView oluşturulduğunda varsayılan dağıtım türü olarak belirlenir. Benim test örneğimde, doldurma için UITextField ve UIImageView kullandım ve bunları yatay bir UIStackView görünümünde gruplandırıyorum.
Kontrollerinizi, Distribution ı Fill olarak ayarlanan bir UIStackView içerisine yerleştirdiğinizde, kontrollerin tümünü doğal boyutlarında tutacak ve alanı doldurmak için bunlardan birini uzatacaktır. Hangisinin en düşük Content Hugging Priority (CHP) sahip olduğuna dikkat ederek hangi kontrolün uzatılacağını belirler. UITextField’ları arasına sekiz birim boşluk ekledim, böylece her birinin boyutunu görebilirsiniz.

Tüm kontrolleriniz aynı CHP’ye sahip ise Xcode, düzenin belirsiz olduğunu şikayet eder. Düzeltebilmek için stackview içerisindeki objelerin boyutları belli olmalı veya ekranın boyutunun yetersiz kalması durumunda önceliğin kimde olduğu belirtilmelidir.

Örneğin üstteki görselde 3 objeden sadece iki objenin genişliği bellidir üçüncü objenin hugging’i low olduğundan geri kalan kısımı o kaplamış.

Başka bir örnek, iki textfield’ın hugging’i high ise bunlar daralacak üçüncü textfield’ın hugging’i low olduğu için kalan alanı bu textfield dolduracaktır.

Sonuç olarak stackview içindeki nesneler kendi özelliklerini (genişlik, yükseklik, hugging veya compression değerleri) baz alarak stackView’i tam olarak doldurmak zorundadırlar.

Fill Equal : Bu tür ile, UIStackView in her kontrol eşit büyüklükte olacaktır. Mümkünse kontroller arasındaki boşluğun tamamı kullanılacaktır. Bu türle CHP’nin önemi yoktur, çünkü her kontrol aynı boyuttadır.

Fill Proportionally : Bu tür keşfetmek için eğlencelidir :) Farklı telefon boyutları ve yönelimleriyle oynayıncaya kadar bu türün etkisini görmek zor. UIStackView, size’ınız büyüyüp küçüldükçe, kontrollerin birbiriyle orantılı olarak aynı oranda boyutlanmasını sağlar. Testimi UITextField’lar yerine UILabel kullanarak değiştirdim.

Dağılımın portrait ve landscape için görünümü şu şekildedir:

Gördüğünüz gibi, farklı düzen boyutları için imageView ve label’ların oranları korunur.

Equal Spacing : Bu dağıtım türü, kontrollerin her biri arasında eşit aralık bırakacak ve kontroller kendisini yeniden boyutlandırmayacaktır. Bunu, etiketler ve görüntüler arasındaki boşluğun eşit boyutunu belirtmek için kırmızı çizgiler çizerek gösterdim.

Equal Centering : Son olarak, son dağıtım türünün bir örnek olmadan görmesi biraz zor. Kontrollerin merkezlerini eşit olarak uzatacaktır. Bunu göstermek için, her bir kontrolün merkezine kırmızı dikey çizgiler çizdim. Kırmızı çizgiler arasındaki mesafe eşit aralıklarla yerleştirilir.

4) Spacing

Aralardaki boşluğu belirler:

Bir UIStackView kullanırken tüm bu seçenekler birbirlerinden oldukça farklı davranırlar. Bazıları, child’ların büyüklüğünü kontrol etme hakkında görüş bildirmişlerdir, diğerleri ise, child’ların istedikleri kadar büyük olmasını ve farklı şekillerde uzamasını sağlamaya çalışmaktadır.

Priority nedir ?
Öncelikle tüm constraint ler priority özelliğine sahiptir. Interface Builder üzerinden herhangi bir constraint tanımladığınızda default olarak priority 1000 set edilir. Priority 1 ile 1000 arasında değerler almaktadır. Değer büyüklüğüne göre öncelik artar. Eğer değeri 1000 ise bu constraint zorunlu bir constraint’tir. 1 ve 999 dahil tüm priority değerine sahip constraint’ler ise optional’dır. Layout oluşturulurken, uygun koşullar altında, optional constraint ler içerisinde doğru denklem elde edilene kadar priority en yüksekten en düşüğe kadar teker teker sağlaması yapılarak denenir.

Örneğin aynı view için hem 1000 priority hem de 999 priority’e sahip iki kural olduğunu varsayalım. 1000 priority ile safe area’ya, 999 priority ile superview’e bağlı olsunuz. Safe area olan bir sürümde çalıştırıldığında 1000 priority’li kural gerçekleştirilebildiği için view, safe area’ya bağlı olarak açılacaktır. Safe area desteklenmeyen bir sürümde (<iOS 11) çalıştırıldığında ise view 1000 priority’li kuralı gerçekleştiremediği için bir sonraki kuralın olup olmadığını kontrol edecek. 999 priority’li kural superview’e bağlı olarak tanımlandığı için bunu gerçekleştirerek view’i bu sürüm için superview’e bağlayacaktır.

UILayoutPriority’nin 4 adet priority seviyesi şöyledir :

Low (250)
Medium (500)
High (750)
Required (1000)

Intrinsic Content Size
Bazı view’lar içeriğine göre kendiliğinden bir boyuta sahiptir. Bunu onların intrinsic content size’ı olarak adlandırılıyor. UIButton ve UILabel buna bir örnektir. İkisinde de içerik olarak bulunan title’a ek olarak ufak marginler ile boyutlandırılmaktadır. Interface Build içine bir Label atıp top ve horizontal constraint tanımı yaparsanız başka hiçbir constraint e ihtiyaç duymayacaktır.

Yukarıdaki örnekte view içersinde 2 adet butonum var. Soldan sağdan zorunlu constraint’ler tanımlanmış durumda ve 2'si arasında 8 point lik bir constraint bulunuyor. Ancak içeriğin boyutunu aldığından burada bir conflict oluşuyor.

Bu örnekte butonların sağında, solunda ve aralarında belli bir uzaklık olmak zorunda.

Bu conflict i çözmenin yolları:
Butonlardan birine sabit boyut verilebilir

Buradaki örnekte 2. butona sabit bir genişlik verdik ve birinci buton içeriği kendiliğinden sıkıştı ve constraint ortadan kalktı.

Aralarındaki boşluk Küçük Eşit ( ≤ ) olarak tanımlanabilir

Aradaki boşluğu 8 pointe eşit veya daha küçük olabileceğini söylediğimizde görseldeki gibi içerik boyutuna göre genişlik alan butonlar iç içe geçti.

Bunlara benzer çözümler üretmek mümkün ancak bu gibi durumlarda hangi contentin bizim için daha öncelikli olduğuna karar vermemiz lazım. Bu yüzden priority yine devreye giriyor

Burada karşımıza Content Hugging ve Content Compression Resistance Priority çıkıyor.

  • Content Hugging Priority : Sarılma
    Bu öncelik constraint ler arasında priority si büyük olanın küçük olanın içeriğine göre büyümesine izin vermiyor. Yeterli olan boyutuna sarılıyor.
  • Content Compression Resistance Priority : Sıkıştırma
    Bu öncelik ise constraintler arasında prioritysi büyük olanın kendi uygun boyutunu korumak için küçük olanı sıkıştırabilmesini sağlıyor.

Peki tüm bunların bizim örneğimiz ile ne alakası var ?

En başa dönecek olursak şöyle bir conflict alıyoruz. Buradaki hatanın tam sebebi 2 butonun da Content Compression Resistance (CCR) priority eşit olduğundan runtime da hangisinin contenti sıkıştırabileceğini anlayamamasıdır. Burada örneğin Button 2 nin Content Hugging Priority (CHP) sini daha yüksek verecek olursak sonuç şu şekilde olacaktır.

Görüldüğü gibi button 2 içeriği kadar boyut aldı ve button 1 e geriye kalan alan doğrultusunda içerik sıkıştırılması yapıldı. Olayı daha iyi anlamak adına birde Button 2'nin font size’ını 15 ten 23'e alıp sonucu inceleyelim:

Sonuç
Autolayout işlemlerinde yapmamız gereken birçok işlemi gördüğünüz gibi stackview hallediyor. Gerekli yerlerde kullanıldığında, yeni bir obje eklenmesi durumunda zaman kaybı oluşturan durumlardan kaçınılmış olunur.

Bir sonraki yazıda görüşmek üzere 🤚

Kaynaklar

Hüseyin Bagana

--

--