iOS 6 Auto Layout Bölüm 2/2

İlk yazımızda eski Struts ve Springs ile arayüz problemlerini nasıl çözebileceğimizi gördük.iOS 6 ile gelen Auto Layout pek çok soruna daha kolay çözümler getiriyor.

İkinci ve son yazımızda constraintler hakkında daha çok şey öğreneceğiz.

Kalın Constraint’ler

Fark ettiyseniz ekranda görünen bazı T-bar’lar diğerlerine göre daha kalın şekilde gösteriliyor. Böyle görünen contraint’lere User Constraint denir. Diğerlerinin aksine bunları silme şansımız var. Ancak bir user constraint sildiğimizde Interface Builder onun yerine silemeyeceğimiz bir constraint ekler. Nedenini birazdan göreceğiz.

User contraintler Document Outline’da mavi ikonludur:

User constraints document outline

Listeden Vertical Space (40) constraintini seçip silelim. 2 button arasındaki T-Bar artık kayboldu ve yerine ekranın aşağısına kadar uzanan yeni bir tane eklendi:
After deleting user constraint

Bu yeni constraintin ikonu mavi yerine pembe ve yazı tipi de normal tiptedir. Anlamı onu silemeyeceğimizdir. Artık 2 button birbiriyle düşeyde bağlantılı değil. Ancak sol taraftan olan bağlantıları devam ediyor.

Buna neden olay şey nedir? Sistem neden yeni bir constraint ekledi? Yanıtı şu:
Her view için, her zaman, kendisini posizyonunu ve ebatlarını belirleyen yeterli sayıda constraint’i mutlaka olmalıdır.

Konu Auto Layout olunca bu kural herzaman hatırlanması gerekir. Yeterli constraint olmadığında Auto Layout hesap yapamaz. Bu çeşit layoutlar uygunsuzdur. Bunların örneklerine sonra bakacağız.

Interface Builder arayüzün doğru görünebilmesi için epey uğraşır. Buttonlarımızın boyutları, içindeki textler ve genişlikleri bilindiğinden – intrinsic content size (önceki yazımızdan hatırlarsınız – hesaplama yapmak oldukça kolay. Üstteki buttonun x koordinatını biliyoruz ve alttaki button ile sol taraftan hizalı, ayrıca alttaki button her zaman yatay olarak merkeze hizalı. Yani tek bilmediğimiz Y koordinatı.

Her iki buttonda dikey alanda birbiri ile bağlantılı olduğundan Y koordinatını bulabiliriz. Ancak bunu tanımlayan constraint i silerseniz Auto Layout için doğru hesaplama yapmak çok kolay olmayacaktır.

Bunu çözmek için Interface Builder’in bir “pin” e ihtiyacı var.

Pin all the buttons

Neyseki uygulamamızı çalıştırdığımızda bir sorun görünmüyor. Ekran önceki gibi karşımızda olsada tasarım mantığımız burada farklılık gösteriyor: 2 buttonda ekranın altına bağlı. Bunun anlamı eğer alttaki button hareket ederse, üstteki onunla birlikte hareket etmeyecek. (belirtmem gerekirki her 2 çözümde uygun. karar tamamen size ve tasarımınıza kalmış)

Bunu denemek için alt buttonla ekranın altı arasındaki yatay constraint i seçelim. Attributes inspector’dan constraintin değerini autodan 40’a çevirelim

buttonlar bağlı olmadığından sadece alttaki button hareket etti. Üsteki duruyor:
Only bottom button moves up

Fark ettiyseniz değeri değiştirdiğimiz constraint artık User Constraint oldu.

Needle ve pin

Buttonları tekrar bağlayalım. Şuana kadar constraintleri buttonları sürüklememiz sırasında elde ettik. Daha sonrasında da bunları oluşturabiliriz.   Cmd tuşuna basarken 2 buttonu seçelim. Sonra Editor menusundan Pin/Vertical Spacing’i seçelim.

Ayrıca alttaki menuden de bunu yapabiliriz:
Shortcut menu pin

Tıkladığınızda açılan menu:
Pin menu

Hangi yöntemi uygularsak uygulayalım artık yeni constraintimiz var.
Pin vertical spacing

Bu yeni constraint yatay düzlemde ve değeride 20 birim. bunun nedeni buttonlar arası mesafenin 20 birim olması. Eski 104 birimlik constraint hala duruyor. Artık ona ihtiyacımız olmadığından silebilirz. Hatırlarsanız daha önce mavi bir constraint sildiğimizde yerine silinemez pembe constraint atanıyordu. Şuanda böyle bir atama yapılmadı. Çünkü onun yerini doldurabilecek başka bir constraintimiz var. özetle interface builder sadece gerekli olduğunda bu işlemi yapar.

Constraint tablomuz aşağıdaki gibi olmalı:
Restored constraints

Yatay alan constraintini seçelim ve değerini 40 yerine standart olarak değiştirelim. böylece 2 button birden harekete edecek. Çünkü artık birbirlerine bağlılar.

Runtime’da bir gezinti

Şuana kadar temel şeyleri gördük. ancak kontrolleri guide’ları kullanarak hizalamayı, aralarına mesafe belirlemeyi biliyoruz. Daha sonra Align ve Pin menulerini nasıl kullanacağımıza değineceğiz.

Interface builder ile oynamak eğlenceli ama bu işin runtime da nasıl çalıştığına bakalım. Aşağıdaki metodu ViewController.m’e ekleyelim:

- (IBAction)buttonTapped:(UIButton *)sender
{
    if ([[sender titleForState:UIControlStateNormal] isEqualToString:@"X"])
        [sender setTitle:@"A very long title for this button"
                forState:UIControlStateNormal];
    else
        [sender setTitle:@"X" forState:UIControlStateNormal];
}

Bu metod basit olarak buttonlarımız bir event aracılığı ile konumlarını değiştirecek. Interface builder üzerinden bu metodu buttonlar ile bağlayalım: Ctrl’ye basılı tutup ekrana sürükleyim ve açılan menuden buttonTapped: i seçelim.
Uygulamayı çalıştıralım ve buttonlara bastığımızda nasıl davrandıklarını görelim.
Long and short titles

Hangi buttona basıldığı farketmeksizin constraintlerimiz sayesinde ekranda doğru bir görünüm elde edeceğiz:

  • Alttaki button herzaman yatay olarak ekranın merkezine hizalıdır.
  • Alttaki button her zaman ekranın altından 20 birim yukarıda yer alır.
  • Üstteki button her zaman alttaki buttonun soluna hizalıdır.

Bunlar arayüzümüzün temel bilgileri. Farklı bir şey deneyelim. buttonları seçin Align menusundan Right Edges’i seçip uygulamayı çalıştırın.

Genişliği ayarlamak

Pin menusunde genişliği ayarlayan bir seçenek var. 2 view için bunu seçtiğinizde Auto Layout 2 view’e hemen aynı genişliği verecektir. Deneyelim.

Buttonlarımızı seçelim ve Pin/widths equally’a basalım. Bu işlem her iki buttona bir constraint ekler:
Buttons widths equally

Not: Eğer bu işlem sonucunda fazladan constraint eklenirse, buttonları seçip Align\Horizontal Centers ‘ı seçin.

Bu tipte constraintleri 1. makalemizde görmüştük. Her zamanki T-Bar yerini aldı.

Document Outline’da bu işlem için constraintimiz yerini aldı:
Equal widths in document outline

Bu buttonun içeriğini değiştirmek boyuta etki edecektir.

İçeriği x olarak değiştirdiğinizde 2 buttonun genişliği oldukça kısaldı. Yukarıdaki buttonun text’i artık sığmıyor:
Top button text no longer fits

Peki interface builder hangi buttonun boyutu esas alacağını nereden biliyor? Dikkatli bakarsak hangi buttona atandığını görebiliriz:
Width constraint on truncated button in document outline
Width constraint on truncated button
Interface Builder boyutları aynı tutmak için buttonu boyutunu olması gerekenden kısa olacak şekilde zorlar.

tabiki istediğimiz bu değil. üstteki buttonu seçelim ve Size to Fit Content from the Editor i işaretleyeim. Button şimdi normal halini aldı ve genişliği belirten constraint kayboldu.
Uygulamayı çalıştıralım. içerdikleri textleri ne olursa olsun buttonların boyutları hep aynı:
Buttons equal widths in app

Aslında text boyutu kısa olduğunda buttonlar kendiliğinden ebatlarını ufaltacaktır hem de tam olmaları gerektiği boyuta. Buna ne diyorduk? “Intrinsic content size

Intrinsic Content Size (varsaylan içerik boyutu)

Auto Layout’tan önce kontrollere ne kadar büyük olmaları gerektiği, sınırları vb. özelliklerini söylemek zorunda kalıyorduk. Ancak şuanda çoğu kontrol için mükemmel şekilde çalışıyor.

Bir label kontrolü, ne kadar geniş ve uzun olacağını içerdiği text uzunluğu, font büyüklüğü vb. nedenlerden dolayı bilir. Aynen buttonda olduğu gibi.

Progress Bar gibi kontrollerde ise yüksekliği bilmek mümkün ancak genişliği bilemeyiz. “Intrinsic content size” bunu bilir. Aslında bu konsept Auto Layout için oldukça önemlidir. Buttonlarla ilgli örneklerimizde görmüştük. Auto Layout ekranı doğru şekillendirebilmek için kontrollerimize ne kadar büyük olmaları gerektiğini sorar. Bu bilgilere görede ekranı oluşturur.

Kendimizin yükseklik ve genişlik bilgilerini girdiğimiz durumlarda Auto Layout bu bilgiyi sormaz. Elle boyutu değiştirdiğimizde Interface Builder değerler için constraint atar. Size to Fit Content komutu ile bizim belirlediğmiz değerler ve buna bağlı constraintler kaybolur.

Genellikle intrinsic content size kullanılır. ancak bazı durumlarda bunu kullanmak uygun olmayacaktır. Ekran boyutundan büyük bir boyuta sahip bir resimi UIImageView’e atadığımızı düşünün. Bu durumda resmin boyutunu kendimiz belirleriz.

Peki buttonlardan birinin girilmiş bir genişlik değeri olduğunu düşünün. Buttonlar kendi boyutlarını hesaplar  ancak elle kendimi değer atayabiliriz.   Üstteki buttonu seçelim ve Pin\Width tıklayalım. Bu bir T-bar ekler:
Button fixed width constraint

Böylece sadece o button için bir constraint ekledik. Document Outline’dan da görebiliriz. Bu sırada button genişliğini 73 birim olarak belirledik.

Uygulamayı çalıştıralım ve buttonlara basalım. Ne oldu? Buttonun boyutu değişti ancak texti daha uzun olduğundan yeni boyuta sığmadı:

Button text clipped

Çünkü üstteki buttonun belirlenmiş bir genişlik değeri var ve aynı 2 buttonda aynı boyda olma zorunluluğu var.

Note: Muhtemelen tasarım aşamasında genişlik için bir constraint atamayız. En iyisi kendisinin belirlemesi. Ancak arayüzle ilgili bir sorun yaşandığında bunu değiştirebiliriz. Değiştirememiz durumunda constraintlere bakmakta fayda var.

Unutmamamız gereken Auto Layout’un doğru hesaplama yapabilmesi için yeterli sayıda constraint olması gerekiyor.

Got enough constraints

Galeri Örneği

Constraintler hakkında yeterince bilgimiz artık var ve arayüz oluştururken nasıl çalıştıklarını biliyoruz. Buradan sonra örneklerle devam edeceğiz.
Favori programcılarımızı gösteren bir galeri uygulaması yapalım. ekran görünümüde aşağıdaki gibi olsun:
The Gallery app

Ekranı 4 eşit parçadan oluşacak. Her bir çeyreğin bir image view i ve label ı olsun. Bunu nasıl yaparız?

Uygulamamızı yapmaya başlayalım. Eski view ve constraintleri silerek veya yeni bir uygulama açarak başlayalım. Yeni projemizin adı “Galeri” olsun. storyboard’u kapatalım.

ViewController.xib ‘i açalım. Object Library’den bir boş bir view atalım ve boyutunu 160×230 olarak değiştirelim. Arkaplan rengi yeşil olsun:

View with auto layout
Bu view’in 4 tane constrainti var. View, button veya label gibi olmadığından intrinsic content size’ı olmaz. Her bir view için pozisyonu ve ebatları gösteren constraintlerin olması gerekiyor.  Merak edenler için 2 tane yatay 2 tane de düşey constraintimizi document outline’dan görebiliriz:
Constraints for UIView in document outline

Yeşil ekranın genişliği superview’in genişliği eksi constraintler olarak hesaplanır. Ekran boyutu değiştiğinde formule göre yeniden hesaplama yapılır. Ekran genişliği 320×460’tan 480×300 olarak değişir. Uygulamayı çalıştırıp ekranı döndürdüğünüzde değişikliği kendinizde görebilirsiniz.

Üstteki view’i seçip Attribute inspector’a gelin. Simulated Metrics’den Orientation değerini Landscape olarak değiştirin:

Simulated metrics landscape

Bu bize ekran döndürüldüğünde view’in nasıl görüneceğini göstermiş olacak. Yeşil view kendi boyutlarını uygun şekilde ayarladı. Orientation değerini portrait’e çevirelim.

Not: Boş viewleri neden oluşturacağımızın 2 temel nedeni var.
a) Diğer viewlerin içeriğini düzenlememize imkan verecekler.
b) Yertutucu olduklarından kendi yazdığımız class, UIView veya UIControl class’larını atayabiliriz.

Ekran döndürüldüğünde view’in değişmesini istemediğimiz durumlarda constraintlere kendimiz değer atamamız yeterli olacaktır. Bunu deneyelim. View’i seçin sırayla Pin menusunden height ve width’i tıklayın.
Böylece 2 tane yeni constraint eklemiş olduk. Width yani genişlik değeri 160 birim, height yani yükseklik değeri ise 230 birim:

Width and height constraints on UIView

Document outline’dan view’e atanmış bu değerleri görebiliriz. Genellikle constraintler 2 farklı view arasındaki ilişkiyi açıklar. örneğin yeşil view ile onu taşıyan gri superview arasındaki düşey ve yatay constraintler – bu değerleri view ve superview arasındaki boy ve genişlik bağlantısı olarak kabul edebilirsiniz.

Uygulamayı çalıştıralım. Portrait modda doğru görünüm var. Ancak ekranı döndürdüğümüzde istediğimizi elde edemedik. View boyutunu yine değiştirdi ve Xcode’dan bir hata aldık:

Gallery[68932:11303] Unable to simultaneously satisfy constraints.
	Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
    "",
    "",
    "",
    "",
    ""
)
Will attempt to recover by breaking constraint

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Hatırlarsanız Auto Layout’un hesaplamayı yapabilmesi için yeterli constraint olmalıydı. Bizim örneğimizde ise gereğinden fazla constrainte sahibiz! “Unable to simultaneously satisfy constraints” uyarısının anlamı constraintler arasında bir çakışma var demektir.

Constraintlere bir daha bakalım:
Conflicting constraints

Yeşil view için 6 tane constraint var. 4 tane boşluklar için önceden verdiğimiz ve 2 tane az önce eklediğimiz boy ve genişlik için olan constraintler. Peki karışıklık nerden çıkıyor?

Portrait modda herhangi bir problem yok çünkü işlem doğru hesaplanıyor. Superview (gri) in genişliği 320 birim. yatay alan ve genişlik değerlerini topladığımızda 320’yi (51 + 160 + 109 = 320 ) elde ediyoruz.   Ayrıca düşey değerler ise benzer şekilde en fazla 460 birim olmalı.

Ancak ekranı döndürdüğümüzde Auto Layout hangi değeri alacağını bilemiyor. Karşılaştığımız sorun bizim geniş değerini veya margin değerlerinden biri kendimizin belirlemesi. Sorunu çözmek için bazılarını silmeliyiz. Örneğimizden devam edersek uygulamanın doğru görünebilmesi için (her iki modda) yapacağımız değişiklik: yatay boşluk değeri gitmeli: Tasarım ekranından önce yatay boşluğu sonra da view’in altında yer alan  yatay alan’ı silelim. Ekran aşağıdaki gibi olmalı:

Conflicting constraints fixed

Şimdi view doğru sayıda constrainte sahip. Ne eksik ne fazla. Uygulamayı çalıştıralım ve hata mesajı alıp almadığımızı görelim. Hata mesajı kayboldu ve görünüm 2 modda da doğru.

Note: Interface Builder gerçekten doğru görünümü elde edebilmemiz için yoğun uğraş verir.  ancak mucize yaratmasını beklemeyin. En azından Auto Layout detaylı hata mesajları vererek sorun olduğunu gösterir. Bu hatalarla ilgili detayları sonraki yazılarımızda inceleyeceğiz.

Görünümü Boyamak

Yeşil view içerisine bir label atalım. Guide’lar bize yerleştirme için yardım oluyor. Çünkü view’imiz label için superview’dir.
Drag label into green view

Label’i ekrandaki gibi konumlandırdığınızda label’i ekranın sol-üst bölümüne bağlayan bir 2 constraint eklenir:

Label constraints

Bu constraintlerin yeşil view’imizin altında gösterildiğini (document outline’da) unutmayalım.

Şimdi yeşil view’in yerini değiştirip görüntüdeki gibi yerleştirelim. View’e ait constraintlerin değiştiğini görebilirsiniz. ancak label için birşey değişmedi. Label aynı yerde durmaya devam ediyor.

Lebel’ı da görüntüdeki gibi alt bölüme hizalayıp konumlandıralım. Yeni bir image view’i sürükleyip bırakalım:
Image view in gallery
Image view, ekranın sağ sol ve üst bölümüne pinlendi. Ancak alt bölümü standart boşluk nedeniyle label’a bağlı.

Bu örnek için gereken ek dosyaları buradan indirebilirsiniz. Zip’i açıp açılan klasörü projenin içine dahil edelim. Ray.png dosyasını image view’imiz için seçelim. Aspet Fit’i seçip ve arkaplan rengini beyaz yapalım. Label’in text’ “Ray” olsun.

Arayüz aşağıdaki gibi olmalı:
Gallery with Ray

Bu arada Interface Builder label’a bir yükseklik constraint’i ekledi. Bu image olarak bir resim verdiğimiz anda gerçekleşti.

Label fixed height

Interface Builder layouttaki belirsizlikleri önlemeye çalışır. Image view’de ve label’da bir yükseklik değeri belirlememiş olsak Auto Layout hesaplamayı yapamaz. (Interface builder şuan için bu durum dikkate almadı   çünkü yeterli sayıda constraint’imiz var)

Diyelimki bir noktada yeşil view’imiz 100 birim daha uzun oldu. Auto Layout bu yeni birim genişliği nasıl dağıtacak? Label aynı kalırken image view’mi 100 birim genişleyecek? veya label genişlerken image view aynı mı kalacak? 100 birim ikisine eşit oranmı paylaştırılacak? veya farklı bir orandamı dağıtılacak?

Auto Layout bu soruların cevabını vermez ama Interface Builder bu problemi label ve image view’e sabit bir boy değeri vererek çözer.
Not:
Bu sorunun aslında çözümü label’ın “Content Compression Resistance Priority” değerini değiştirmek. Bunun detaylarına sonra bakacağız. Şimdi Size inspector’a gelip label için vertical Content Compression Resistance Priority değerini 751 yapalım. boy için verilen constraint kaybolur.

Diğer resimleri ekleyelim

Yeşil view’i ekranın sol üst köşesine taşıyalım. Ekranın kenarına yerleştiğinden constraint hala var. ancak değeri 0 – bu değer ekranda gördüğünüz gibi çizgilerle gösterilir:
View in top-left corner

Gördüğünüz gibi view kenara yaslıda olsa hala onu bağlayan bir constraint değerine ihtiyacı var. Değeri sıfır bile olsa.

yeşil view’i seçip Cmd-D ile çoğaltalım. yeni view’i sağa yaslayalım.

Green view in top-right corner

2 yeni daha view açıp alt köşelere hizalayalım. Arkaplanlarını da değiştirelim:

Gallery design

Gayet yakışıklı programcılar değilmi =)

Uygulamayı çalıştıralım. Portrait görünümde gayet iyi. ancak landscape modda iyi görünmüyor:
Gallery looks bad in landscape

Sorunun nedeni belli. Boy ve genişlik için elle değer girdiğimizden view’lar her zaman aynı boy ve genişlikte kalmak istiyor. Document Outline’dan genişlik(160) ve boy(230) değerlerini içeren constraintleri tüm view’ler için silelim. Uygulamayı çalıştıralım:
Still looks bad in landscape

Oldukça kötü. Problemi çözdüğümüzü sandık ancak yapmamız gereken başka şey daha var. 4 view’ide seçip Pin menusundan sırasıyla Widths Equally ve Heights equally’i seçin. Uygulamayı çalıştırdığımızda ekranı döndürün. Hiçbir değişiklik olmadı değilmi ?

Ekran görüntüsüne bakarsanız 4 view’inde aynı boyu oldupunu ve aynı genişlikte olduğunu göreceksiniz (yeşil ve kahverengi view’ler altta kalmış). Yine constraintlerle ilgili bir sorun var. Sadece boy ve genişlik değil. Başka bir tane.
Neyseki view’lerdeki constraintlere bakarsanız yatay ve dikey alanlar için olan constraintlerin görünümü zorladıklarını görebilirsiniz:
Bad H-space

Daha kötüsü bu constraintleri silemiyoruz. T-bar kalın ve mavi değil. Interface Builder problem olmasın diye yerleştirmiş.  Neden bunu yaptığının yanıtı ise 4 view’de eşit ölçülerde olmalı ancak hesaplama için yeterli constraint bulunmuyor. Bu nedenle Auto Layout hesaplamayı, view’lar arasındaki bağlantıyı (örneğin “Ray” ve “Matthijs”) çözemediğinden tam olarak yapamıyor. Auto Layout bunu çözemiyorsa bizim ona yardımcı olmamız gerek:

To be related ,

Ray ve Matthijs viewlerini seçelim ve Pin menusunden Horizonal Spacing i seçelim. Çünkü yanyanalar ve aralarına yatay bir constraint Auto Layout’un hesaplamasına ve aralarında bağlantı olduğunu bilmesi içi yeterli olacaktır.

Önemli: Interface Builder constraintleri eklediğimiz zaman kendi oluşturduklarını silmez. Ancak onu User Constraint’e çevrirsek yapılabilir. Çevirmeden silmeyi denersek “Unable to simultaneously satisfy constraints” hatası alırız.
Uygulamayı çalıştıralım:
Landscape a bit better

Biraz daha düzgün. 4 view’de eşit genişlikte. ancak boyları hala eşit değil. Çözüm neredeyse aynı. Ray ve Dennis Ritchie viewleri arasında düşey constraint ekleyerek birbirine bağlayalım. Uygulamayı çalıştırdığımızda bu kez istediğimizi elde ettik:

Gallery landscape OK

Fark ettiyseniz “Dennis Ritchie” label’i image view’in ortasına denk gelmiyor. Aslında bu durum text’i girdiğimizden bu yana var. Label her nekadar ortalanmış olsada Interface Builder bunu değiştirmeyi uygun gördü. Bunu düzeltmek için Align menusunden Horizonal Center’i seçin.

image view hakkında ufak bir not: Kendimiz değer girmediğimiz için boyutları otomatik olarak değişti. image view bu durumda landscape moda sığmaz. Eğer image view’in aspect ratio’da kalmasını istiyorsanız hiç şansınız yok. Interface builder ile bunu yapamayız:
Aspect ratio on images

Maalesef Interface Builder aspect ratio’yu korumak için bir çalışma yapmaz. Bunu yapabilmek için kod yazmamız gerekiyor. Bunu Auto Layout hakkındaki sonraki yazılarımızda işleyeceğiz.

İpucu: Daha önce arayüzün nasıl görüneceği ile ilgili önizleme yapmak için Simulated Metrics altındaki Orientation setting’i kullanmıştık.

Ekranın tamamını seçelim. Simulated Metrics, atındaki Size değerini Freeform olarak atayalım. Bu ana ekranı istediğimiz gibi şekillendirmemizi sağlayacak. Auto Layout arayüz için tekrar hesap yapar:
Freeform

Bunu kullanırken dikkatli olmamız gerekiyor. Bazen Interface Builder boyutları ayarlamak için yeni constraintler ekleyebilir. Bu nedenle bazen ekran sınırlarına taşmalar yaşanabilir.

Bundan sonrası?

Buraya kadar geldiyseniz – tebrikler! – Auto Layout hakknda epey şey öğrendik. Ancak öğrenecek daha çok şey var.
Bu makale ile iOS 6 by Tutorials kitabındaki Auto Layout hakkındaki bilgilerin bir bölümünü inceledik. 2. bölüm daha gerçekçi örnekleri ve bilmemiz gereken şeyleri içeriyor olacak.

One response

  1. Burhan Aksendir Avatar
    Burhan Aksendir

    Teşekkür ederim. Çok faydalı oldu.

Leave a Reply

Your email address will not be published. Required fields are marked *