Bir kapsayıcı görünümünde birden çok görünümü eşit aralıklarla yerleştirme


279

Otomatik Yerleşim hayatımı zorlaştırıyor. Teorik olarak, geçiş yaptığımda gerçekten yararlı olacaktı, ama her zaman onunla savaşıyorum.

Yardım bulmaya çalışmak için bir demo projesi yaptım. Görünüm yeniden boyutlandırıldığında görünümler arasındaki boşlukların eşit olarak nasıl artırılacağını veya azaltılacağını bilen var mı?

İşte üç etiket (elle dikey olarak eşit aralıklarla yerleştirilmiş):

image1

İstediğim, döndürdüğümde aralıklarını (görünüm boyutunu değil) eşit olarak yeniden boyutlandırmalarıdır. Varsayılan olarak, üst ve alt görünümler merkeze doğru ezilir:

image2


belki bir etiketten diğerine sınır koymak ve "o zamandan büyük veya eşittir" ilişkisini ayarlamak yardımcı olacaktır
BergP

programlı olarak örneğin bu NSLayoutConstraint: + (id) kısıtlaması ile bu yöntemi kullanarak sabiti: (CGFloat) c
BergP

Otomatik Düzen kullanarak bu yaklaşımı genelleştiren genel bir UITabBar değiştirme kaynaklı. Otomatik Mizanpaj kısıtlamalarımı nasıl oluşturduğumu görmek için testleri kontrol edebilirsiniz.GGTabBar
Goles

Yanıtlar:


211

Benim yaklaşımım bunu arayüz oluşturucuda yapmanıza izin veriyor. Yaptığınız şey, yüksekliklerle eşit olarak eşleştirmek için ayarladığınız 'boşluk görünümleri' oluşturmaktır. Ardından etiketlere üst ve alt kısıtlamalar ekleyin (ekran görüntüsüne bakın).

resim açıklamasını buraya girin

Daha spesifik olarak, 'Spacer View 1' üzerinde 1000'den daha düşük önceliğe sahip bir yükseklik sınırlaması ve diğer tüm 'spacer görünümlerine' eşittir. 'Spacer View 4', denetlemek için alt alan kısıtlamasına sahiptir. Her etiket, en yakın 'boşluk görünümleri' için üst ve alt sınırlamalara sahiptir.

Not: Denetlemek için etiketlerinizde ekstra üst / alt boşluk kısıtlamaları OLMADIĞINIZDAN emin olun; sadece 'uzay manzarasına' olanlar. Üst ve alt kısıtlamalar sırasıyla 'Space View 1' ve 'Spacer View 4' üzerinde olduğu için bu tatmin edici olacaktır.

Duh 1: Görüşümü kopyaladım ve sadece manzara moduna soktum, böylece işe yaradığını görebiliyordum.

Duh 2: 'Aralayıcı görünümler' şeffaf olabilirdi.

Duh 3: Bu yaklaşım yatay olarak uygulanabilir.


10
Bu çalışıyor. Aslında, aralayıcı görünümleri gizlenebilir ve yine de doğru düzeni oluştururlar.
paulmelnikow

Bu süper yardımcı oldu. Tıpkı aralayıcı görünümlerini gizli olarak işaretleme hakkında yorum yapıldı. Ardından bunları film şeridinde / xib'inizde görebilirsiniz, ancak uygulamanızda görünmezler. Çok hoş.
shulmey

Birkaç saat tekrarlanan denemelerden sonra neredeyse çalışmaya başladım . Ne yazık ki Xcode, üst-alan-düğme ve alt-alan kısıtlamalarımı silmeye, düğmeler ve aralayıcılar arasındaki zinciri kırmaya ve bunları, işe yaramayan rastgele üst alandan denetime kadar kısıtlamalarla değiştirmeye devam ediyor.
13'te

Aynı yaklaşım benim için yatay düzende işe yarıyor - eşit genişlik boşluk görünümleriyle ayrılmış sabit genişlik görünümlerim var. Herhangi bir kod ile karıştırmak gerekmez harika. Teşekkürler!
Kamil Nomtek.com

2
Ara parça kullanmaya gerek yoktur. Cevabımı aşağıda görebilirsiniz.
smileBot

316

BAK, ARA YOK!

Orijinal cevabımın, özellikle @ Rivera'nın yararlı önerilerinin yorumlar bölümündeki önerilere dayanarak, orijinal yanıtımı basitleştirdim.

Bunun ne kadar basit olduğunu göstermek için gifler kullanıyorum. Umarım gifleri yararlı bulursunuz. Gif'lerle ilgili bir sorununuz olması durumunda, eski cevabı aşağıda düz ekran çekimlerine ekledim.

Talimatlar:

1) Düğmelerinizi veya etiketlerinizi ekleyin. 3 düğme kullanıyorum.

2) Her düğmeden denetime bir merkez x kısıtlaması ekleyin:

resim açıklamasını buraya girin

3) Her düğmeden alt düzen kısıtlamasına bir sınırlama ekleyin:

resim açıklamasını buraya girin

4) Yukarıdaki # 3'e eklenen kısıtlamayı aşağıdaki gibi ayarlayın:

a) kısıtlamayı seçin, b) sabiti kaldırın (0'a ayarlı), c) çarpanı aşağıdaki gibi değiştirin: + 1 düğmelerinin sayısını alın ve üstten başlayarak çarpanı buttonCountPlus1: 1 olarak ayarlayın ve sonra buttonCountPlus1 : 2 ve son olarak buttonCountPlus1: 3 . (İlginizi çekiyorsa, bu formülü nereden aldığımı aşağıdaki eski cevapta açıklarım).

resim açıklamasını buraya girin

5) İşte bir demo çalışıyor!

resim açıklamasını buraya girin

Not: Düğmeleriniz daha yüksek yüksekliklere sahipse, kısıtlama düğmenin altından olduğu için bunu sabit değerde telafi etmeniz gerekir.


Eski Cevap


Apple'ın belgelerine ve Erica Sadun'un mükemmel kitabına ( Auto Layout Demystified ) söylediklerine rağmen, ara parçaları olmadan görünümleri eşit olarak boşluklandırmak mümkündür . Bu, IB'de ve kod olarak eşit aralıklarla yerleştirmek istediğiniz herhangi bir sayıda öğeyi kodlamak için çok kolaydır. Tek ihtiyacınız olan "bölüm formülü" olarak adlandırılan bir matematik formülü. Bunu yapmak açıklamaktan daha kolaydır. IB'de göstererek elimden geleni yapacağım, ancak kodda yapmak da kolay.

Söz konusu örnekte,

1) her etiketi merkez kısıtlaması olacak şekilde ayarlayarak başlayın. Bunu yapmak çok basit. Her bir etiketten alta doğru sürüklemeyi kontrol etmeniz yeterlidir.

2) Shift tuşunu basılı tutun, çünkü kullanacağımız diğer kısıtlamayı da ekleyebilirsiniz, yani "alt boşluktan alt düzen kılavuzuna".

3) "Alttan alta yerleşim düzeni kılavuzu" ve "kabın içinde yatay olarak ortala" yı seçin. Bunu 3 etiketin tümü için yapın.

Her bir etikete bu iki kısıtlamayı eklemek için shift tuşunu basılı tutun

Temel olarak, koordinatını belirlemek ve toplam etiket sayısı artı 1'e bölmek istediğimiz etiketi alırsak, dinamik konumu elde etmek için IB'ye ekleyebileceğimiz bir numaramız olur. Formülü basitleştiriyorum, ancak yatay boşluğu veya hem dikey hem de yatay olarak ayarlamak için kullanabilirsiniz. Süper güçlü!

İşte çarpanlarımız.

Etiket1 = 1/4 = .25,

Etiket2 = 2/4 = .5,

Etiket3 = 3/4 = .75

(Düzenle: @Rivera, oranları doğrudan çarpan alanında kullanabileceğinizi ve xCode ile matematik yapmayı yorumladı!)

4) Şimdi Label1'i ve alt kısıtlamayı seçelim. Bunun gibi: resim açıklamasını buraya girin

5) Özellik Denetçisinde "İkinci Öğe" yi seçin.

6) Açılır menüden "İlk ve ikinci öğeyi geri çevir" i seçin.

7) Sabit ve wC hAny değerini sıfırlayın. (Gerekirse buraya ofset ekleyebilirsiniz).

8) Bu kritik kısımdır: Çarpan alanına ilk çarpanımızı 0.25 ekleyin.

9) Etiketin y merkezine ortalamak istediğimiz için, üstteki "İlk öğe" yi "Merkez" olarak ayarlayın. Tüm bunlar nasıl görünmeli.

resim açıklamasını buraya girin

10) Her etiket için bu işlemi tekrarlayın ve ilgili çarpanı takın: Etiket2 için 0.5 ve Etiket3 için 0.75. İşte tüm kompakt cihazlarla her yönde son ürün! Çok basit. Kod yığınları ve aralayıcılar içeren birçok çözüme baktım. Bu konu hakkında gördüğüm en iyi çözüm.

Güncelleme: @kraftydevil, Alt mizanpaj kılavuzunun xibs'de değil, yalnızca film şeridinde göründüğünü ekler. Xibs içinde 'Konteyner için Alt Boşluk' kullanın. İyi yakalama!

resim açıklamasını buraya girin


2
Hala bununla mücadele ediyorum. Xcode 6 kullanmanız gerektiğini düşünüyorum çünkü Xcode 5 kısıtlamalarında 'wC hAny' seçeneği yok. Talimatlarınızı takip ettiğimde, tüm alt görünümler üst merkeze yapışır.
kraftydevil

4
@kraftydevil AFAIK Alt mizanpaj kılavuzu yalnızca film şeritlerinde görünür, xib'lerde değil. Xibs içinde 'Konteyner için Alt Boşluk' kullanın.
Timur Kuchkarov

6
Oh - ayrıca Xcode 6'daki IB'nin oran çarpanlarını desteklediğini belirtmek gerekir, böylece "1: 4", "2: 5", "3: 4" vb.
Gibi şeyleri koyabilirsiniz

3
Bunu yatay olarak nasıl yapacağınızı anlamaya çalışmak - soldan yolun ilk TextView 1/3'ü ve ikinci bir TextView 2/3 (yolun geri kalanı) ... ... (EDIT) anladım - ilk 1/3 (soldan bir)
İz

3
Yatay aralık için, her alt görünüm için denetime izleyen kısıtlamaları ayarlayın ve sonra oran çarpanını ayarlayın. 5: 1, 5: 2, 5: 3 vb. Soldan sağa hareket eder.
user3344977

98

Çok hızlı Arayüz Oluşturucu çözümü:

Herhangi bir görünümün bir denetim içinde eşit aralıklarla yerleştirilmesi için, her birine yatay yerleşim için "Merkez X denetimini hizalamak için kısıtlama" veya dikey yerleşim için "Merkez Y denetimini hizala" seçeneğini belirleyin ve Çarpanı şu şekilde ayarlayın N:p( NOT: bazı şansınız daha iyi p:N- aşağıya bakınız )

nerede

N = total number of views, ve

p = position of the view including spaces

İlk pozisyon 1, sonra boşluk, sonraki pozisyonu 3 yapar, böylece p bir seri olur [1,3,5,7,9, ...]. Herhangi bir sayıda görünüm için çalışır.

Yani, yer açmak için 3 görünümünüz varsa, şöyle görünür:

IB'de görünümlerin eşit olarak nasıl dağıtılacağını gösteren örnek

DÜZENLEME Not: Hizalama sınırlamanızın ilişki sırasına göre N:pveya seçimi p:Nbağlıdır. "İlk Öğe" Superview.Center p:Nise, Superview.Center "İkinci Öğe" ise kullanabilirsiniz N:p. Şüpheniz varsa, ikisini de deneyin ... :-)


Başka bir dile geçerseniz bu çözüm tasarımı yansıtmaz
wod

@wod Ne demek istiyorsun? Neyi başka bir dile çevirirsiniz? Ve tam olarak ne kırılır?
Mete

4
elemanlar aynı boyutta değilse ne olur? bu örüntü düzgün çalışmayacak değil mi?
ucangetit

2
Bu çözümün nasıl doğru olduğunu anlamıyorum? Ekranın kenarı ile dış elemanlar arasındaki boşluk, dış elemanlar ve orta eleman arasındaki boşluktan farklıdır?
myles

6
Bu benim için "olduğu gibi" çarpanları tersine çevirmek zorunda kaldım (örneğin ilk öğeden 3: 1 1: 3'e dönüşür). Kimseye yardım ederse, bunu oraya atmak.
Ces

70

İOS 9'dan itibaren Apple bunu (uzun zamandır beklenen) ile çok kolay hale getirdi UIStackView. Arayüz Oluşturucu'da içermek istediğiniz görünümleri seçin ve Editör -> Yerleştir -> Yığın görünümü'nü seçin. Yığın görünümü için uygun genişlik / yükseklik / kenar boşluğu kısıtlamalarını ayarlayın ve Distribution özelliğini 'Eşit aralık' olarak ayarladığınızdan emin olun:

Tabii ki, iOS 8 veya daha düşük bir sürümü desteklemeniz gerekiyorsa, diğer seçeneklerden birini seçmeniz gerekir.


Evet, bunun retro uyumluluğa sahip olmaması üzücü, bu nedenle uygulamanızın IOS8 @Mete yanıtı için desteğe ihtiyacı olana kadar şimdilik en iyisi.
ZiggyST

51

Autolayout'u sevmek ve nefret etmek için bir rollercoaster yolculuğuna çıktım. Bunu sevmenin anahtarı aşağıdakileri kabul etmek gibi görünüyor:

  1. Arayüz üreticisinin düzenleme ve "yararlı" kısıtlamaların otomatik oluşturulması, en önemsiz durum hariç herkes için işe yaramaz
  2. Ortak işlemleri basitleştirmek için kategoriler oluşturmak hayat kurtarıcıdır çünkü kod çok tekrarlayıcı ve ayrıntılıdır.

Bununla birlikte, denediğiniz şey basit değildir ve arayüz oluşturucuda başarılması zor olacaktır. Kod yapmak oldukça basittir. Bu kod, viewDidLoadbunları nasıl istediğinizi içeren üç etiket oluşturur ve konumlandırır:

// Create three labels, turning off the default constraints applied to views created in code
UILabel *label1 = [UILabel new];
label1.translatesAutoresizingMaskIntoConstraints = NO;
label1.text = @"Label 1";

UILabel *label2 = [UILabel new];
label2.translatesAutoresizingMaskIntoConstraints = NO;
label2.text = @"Label 2";

UILabel *label3 = [UILabel new];
label3.translatesAutoresizingMaskIntoConstraints = NO;
label3.text = @"Label 3";

// Add them all to the view
[self.view addSubview:label1];
[self.view addSubview:label2];
[self.view addSubview:label3];

// Center them all horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

// Center the middle one vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

// Position the top one half way up
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:0.5 constant:0]];

// Position the bottom one half way down
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:1.5 constant:0]];

Dediğim gibi, bu kod birkaç kategori yöntemi ile çok basitleştirilmiştir UIView , ancak netlik için burada uzun bir yol yaptım.

Kategori ilgilenenler için burada ve belirli bir eksen boyunca bir dizi görüntüyü eşit aralıklarla yerleştirmek için bir yöntemi var.


Siz efendim, cankurtaransınız. Şimdiye kadar # 1'i anlamadım. Arayüz oluşturucu beni deli ediyor, ama aynı şeyleri yapabileceğini düşündüm. Zaten kodu kullanmayı tercih ederim, bu yüzden bu mükemmel, ve kategori yöntemlerini hemen alacağım.
nothappybob

Kesinlikle oldukça yakın olsa da, bu istenen soruyu tam olarak çözmez (alt boyutlar arasında eşit aralıklarla görünüm boyutunu aynı tutmak). Bu çözüm , rafine edilmiş genel vaka yanıtıdır.
smileyborg

21

Bu çözümlerin çoğu, orta öğeyi alıp ortalayabilmeniz için tek sayıda öğenin olmasına bağlıdır. Eşit olarak dağıtılmasını istediğiniz çok sayıda öğeniz varsa ne olur? İşte daha genel bir çözüm. Bu kategori, herhangi bir sayıda öğeyi dikey veya yatay eksen boyunca eşit olarak dağıtacaktır.

4 etiketi kendi denetimlerinde dikey olarak dağıtmak için örnek kullanım:

[self.view addConstraints:
     [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                        relativeToCenterOfItem:self.view
                                                    vertically:YES]];

NSLayoutConstraint + EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of views to be evenly distributed horizontally
 * or vertically relative to the center of another item. This is used to maintain an even
 * distribution of subviews even when the superview is resized.
 */
+ (NSArray *) constraintsForEvenDistributionOfItems:(NSArray *)views
                             relativeToCenterOfItem:(id)toView
                                         vertically:(BOOL)vertically;

@end

NSLayoutConstraint + EvenDistribution.m

@implementation NSLayoutConstraint (EvenDistribution)

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = (2*i + 2) / (CGFloat)([views count] + 1);
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}

@end

1
Tüm kısıtlamaları kaldırarak ve hemen sonra, bu nesnelere Genişlik ve Yükseklik kısıtlamaları ekleyerek, sonra da yöntem kısıtlamalarıForEvenDistributionOfItems: relativeToCenterOfItem: vertically:
carlos_ms

@carlos_ms Kodunuzu görmek isterim, çünkü çift sayıda öğeyi denediğimde bu kod cihaz yönlerini değiştirirken mükemmel çalışır. Yanlışlıkla çakışmaya neden olan başka kısıtlamalara (otomatik kısıtlama gibi) sahip olmadığınızdan emin misiniz?
Ben Dolman

İşte 4 etiket oluşturma ve bunları dikey eksen boyunca eşit aralıklarla yerleştirme örneği: gist.github.com/bdolman/5379465
Ben Dolman

20

Doğru ve en kolay yol Yığın Görünümlerini kullanmaktır.

  1. Etiketlerinizi / görünümlerinizi Yığın Görünümüne ekleyin :

resim açıklamasını buraya girin

  1. Yığın Görünümü ve seti seçin Dağılımı olmak Eşit Aralığı :

resim açıklamasını buraya girin

  1. Yığın Görünümü'ne ve güncelleme çerçevelerine en yakın komşu kısıtlamalarına Boşluk ekleyin :

resim açıklamasını buraya girin

  1. Tüm etiketlere Yükseklik kısıtlamaları ekleyin (isteğe bağlı). Yalnızca İç Boyutu olmayan görünümler için gereklidir). Örneğin, etiketlerin burada yükseklik kısıtlamalarına ihtiyacı yoktur ve örneğin yalnızca numberOfLines = 3 veya 0 değerini ayarlaması gerekir.

resim açıklamasını buraya girin

  1. Önizlemenin Keyfini Çıkarın:

resim açıklamasını buraya girin


2
Bu> = iOS 9.0'dır, bu yüzden uygulamaya başlamadan önce dağıtım hedefinizi kontrol edin :) Bunun eklendiğini görmek harika!
DivideByZer0

1
2018 şimdi, yığın görünümünü kullanın
Jingshao Chen

17

PureLayout açık kaynak kütüphanesine göz atın . Görünümleri dağıtmak için, her görünüm arasındaki boşluğun sabit olduğu (görünüm boyutunun gerektiği gibi değiştiği) ve her görünümün boyutunun sabit olduğu (görünümler arasındaki boşluğun gerektiği gibi değiştiği) varyantları içeren birkaç API yöntemi sunar. Bunların hepsinin , herhangi bir "ara görünümler" kullanımı.

Gönderen NSArray + PureLayout.h :

// NSArray+PureLayout.h

// ...

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                         withFixedSpacing:(CGFloat)spacing;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                            withFixedSize:(CGFloat)size;

// ...

Her şey açık kaynak olduğundan, bunun spacer görünümleri olmadan nasıl elde edildiğini görmek istiyorsanız, uygulamaya bakın. (Bu yararlanarak hem bağlıdır constant ve multiplier kısıtlamaları için.)


İyi iş! Yine de repoyu yeniden adlandırmalısınız, böylece cocoapods aracılığıyla kullanılabilir hale getirebilirsiniz.
jrturton

9

Benzer bir sorun yaşıyorum ve bu gönderiyi keşfettim. Ancak, şu anda verilen cevapların hiçbiri sorunu istediğiniz şekilde çözmez. Boşluğu eşit yapmazlar, aksine etiketlerin merkezini eşit olarak dağıtırlar. Bunun aynı olmadığını anlamak önemlidir. Bunu göstermek için küçük bir diyagram oluşturdum.

Aralık Çizimini Görüntüle

Tüm 20pt boyunda 3 görünüm vardır. Önerilen yöntemlerden herhangi birini kullanmak, görünümlerin merkezlerini eşit olarak dağıtır ve size resimli düzeni verir. Görünümlerin y merkezinin eşit aralıklarla yerleştirildiğine dikkat edin. Bununla birlikte, denetim ve üstten görünüm arasındaki boşluk 15pt iken, alt görünümler arasındaki boşluk sadece 5pt'dir. Görüşlerin eşit aralıklarla yerleştirilmesi için bunların her ikisi de 10pt olmalıdır, yani tüm mavi oklar 10pt olmalıdır.

Yine de, henüz iyi bir genel çözüm bulamadım. Şu anda en iyi fikrim, alt görünümler arasına "aralık görünümleri" eklemek ve aralık görünümlerinin yüksekliklerini eşit olarak ayarlamaktır.


1
İyi çalışan gizli boşluk bırakıcı görünümlerinin çözümünü kullandım.
paulmelnikow

8

Bunu tamamen IB'de çözebildim:

  1. Alt görünümlerinizin her birinin merkezini Y denetimin alt kenarına hizalamak için kısıtlamalar yapın.
  2. Bu kısıtlamaların her birinin çarpanını 1 / 2n, 3 / 2n, 5 / 2n,…, n-1 / 2n olarak ayarlayın; burada n, dağıttığınız alt görünümlerin sayısıdır.

Üç etiketiniz varsa, bu kısıtlamaların her birine çarpanları 0.1666667, 0.5, 0.833333 olarak ayarlayın.


1
Aslında (2n-1) / n'ye kadar 1 / n 3 / n 5 / n 7 / n yapmak zorunda kaldım
Hamzah Malik

5

Mükemmel ve basit bir yöntem buldum. Otomatik düzen boşlukları eşit olarak yeniden boyutlandırmanıza izin vermez, ancak görünümleri eşit olarak yeniden boyutlandırmanıza izin verir. Alanlarınız arasına bazı görünmez görünümler koyun ve otomatik düzende aynı boyutta kalmasını söyleyin. Mükemmel çalışıyor!

İlk XIB

Gerilmiş XIB

Yine de bir şey not; arayüz tasarımcısının boyutunu küçültdüğümde, bazen kafası karıştı ve olduğu yerde bir etiket bıraktı ve boyutun garip bir miktarla değiştirilmesi durumunda bir çelişki vardı. Aksi takdirde mükemmel çalıştı.

edit: Ben çatışma bir sorun haline geldi bulundu. Bu nedenle, aralık kısıtlamalarından birini aldım, sildim ve onun yerine iki veya daha büyük ve eşit veya daha az eşit olan iki kısıtlama koydum. Her ikisi de aynı boyuttaydı ve diğer kısıtlamalardan çok daha düşük önceliğe sahipti. Sonuç, başka bir çatışma değildi.


4

Ben Dolman'ın cevabına dayanarak, bu görüşler daha eşit bir şekilde dağıtılır (dolgu vb. İle):

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    CGFloat min = 0.25;
    CGFloat max = 1.75;
    CGFloat d = (max-min) / ([views count] - 1);
    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = i * d + min;
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}


3

Etiketlerle bu en azından iyi çalışır:

@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|

Birincisi ikincisi ve ikincisi üçüncüsü ve üçüncüsü birincisi ile aynı genişliğe sahipse, hepsi aynı genişliği alacaktır ... Bunu hem yatay (H) hem de dikey olarak (V) yapabilirsiniz.


3

hızlı 3 sürüm

let _redView = UIView()
        _redView.backgroundColor = UIColor.red
        _redView.translatesAutoresizingMaskIntoConstraints = false

        let _yellowView = UIView()
        _yellowView.backgroundColor = UIColor.yellow
        _yellowView.translatesAutoresizingMaskIntoConstraints = false

        let _blueView = UIView()
        _blueView.backgroundColor = UIColor.blue
        _blueView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(_redView)
        self.view.addSubview(_yellowView)
        self.view.addSubview(_blueView)

        var views = ["_redView": _redView, "_yellowView": _yellowView, "_blueView":_blueView]

        var nslayoutConstraint_H = NSLayoutConstraint.constraints(withVisualFormat: "|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_H)

        var nslayoutConstraint_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[_redView(60)]", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_V)


        let constraint_red = NSLayoutConstraint.init(item: self.view, attribute: .centerY, relatedBy: .equal, toItem: _redView, attribute: .centerY, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_red)

        let constraint_yellow = NSLayoutConstraint.init(item: self.view, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .centerX, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_yellow)

        let constraint_yellow1 = NSLayoutConstraint.init(item: _redView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 0.5, constant: 0)
        self.view.addConstraint(constraint_yellow1)

        let constraint_yellow2 = NSLayoutConstraint.init(item: _blueView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 1.5, constant: 40)
        self.view.addConstraint(constraint_yellow2)

1
Bu kodun sorulara nasıl yanıt verdiğinin detaylandırılması gelecekteki ziyaretçilere yardımcı olacaktır.
JAL

2

İlk cevaptan bu yana bir süre geçtiğini biliyorum, ama aynı problemle daha yeni karşılaştım ve çözümümü paylaşmak istiyorum. Gelecek nesiller için ...

ViewDidLoad üzerinde görüşlerimi ayarladım:

- (void)viewDidLoad {

    [super viewDidLoad];

    cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [self.view addSubview:cancelButton];

    middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    middleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
    [self.view addSubview:middleButton];

    nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    [nextButton setTitle:@"Next" forState:UIControlStateNormal];
    [self.view addSubview:nextButton];


    [self.view setNeedsUpdateConstraints];

}

Ve sonra, updateViewConstrains üzerinde, önce tüm kısıtlamaları siliyorum, sonra görünümler sözlüğünü oluşturuyorum ve sonra görünümler arasında kullanılacak alanı hesaplıyorum. Bundan sonra, sadece kısıtlamaları ayarlamak için Visual Language Format kullanın:

- (void)updateViewConstraints {


    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);

    float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
    NSNumber *distancies=[NSNumber numberWithFloat:distance];

//    NSLog(@"Distancies: %@", distancies);
//    
//    NSLog(@"View Width: %f", self.view.bounds.size.width);
//    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
//    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
//    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);



    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                   options:NSLayoutFormatAlignAllBaseline
                                                                   metrics:@{@"dis":distancies}
                                                                     views:viewsDictionary];


    [self.view addConstraints:constraints];



    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                          options:0
                                                          metrics:nil
                                                            views:viewsDictionary];
    [self.view addConstraints:constraints];



}

Bu yöntemle ilgili iyi olan şey, çok az matematik yapmanız gerektiğidir. Bunun mükemmel bir çözüm olduğunu söylemiyorum, ama elde etmeye çalıştığım düzen için çalışıyorum.

Umut ediyorum bu yardım eder.


2

Benzersiz boyutları olsa bile, herhangi bir sayıda alt görünümü dikey olarak merkezleyecek bir çözüm. Yapmak istediğiniz, orta düzey bir kap yapmak, denetimde ortalamak, daha sonra tüm alt görünümleri kapsayıcıya koymak ve bunları birbirine göre düzenlemek. Ancak çok önemli olarak, bunları kabın üst ve alt kısımlarıyla da sınırlandırmanız gerekir , böylece konteyner doğru şekilde boyutlandırılabilir ve denetimde ortalanabilir. Alt görüşlerinden doğru yüksekliği belirleyerek, kap dikey olarak ortalanabilir.

Bu örnekte, selftüm alt görünümleri ortaladığınız denetimdir.

NSArray *subviews = @[ (your subviews in top-to-bottom order) ];

UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.translatesAutoresizingMaskIntoConstraints = NO;
for (UIView *subview in subviews) {
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    [container addSubview:subview];
}
[self addSubview:container];

[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]];

if (0 < subviews.count) {
    UIView *firstSubview = subviews[0];
    [container addConstraint:[NSLayoutConstraint constraintWithItem:firstSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
    UIView *lastSubview = subviews.lastObject;
    [container addConstraint:[NSLayoutConstraint constraintWithItem:lastSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];

    UIView *subviewAbove = nil;
    for (UIView *subview in subviews) {
        [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
        if (subviewAbove) {
            [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                     toItem:subviewAbove attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f]];
        }
        subviewAbove = subview;
    }
}

Bu, ortalanması gereken farklı boyutlardaki görünümleri kullanırken en iyi çözümdür.
noobsmcgoobs

2

Sorunumu çarpan özelliğini kullanarak çözdüm. Tüm vakalarda işe yaradığından emin değilim, ama benim için mükemmel çalıştı. Xcode 6.3 FYI kullanıyorum.

Yaptığım şey şuydu:

1) Düğmelerimin 320px genişlikli bir ekrana yerleştirilmesini 320px'lik bir cihaza bakmasını istediğim şekilde dağıttım.

1. adım: düğmelerin konumlandırılması

2) Sonra tüm düğmelerimi denetlemek için önde gelen bir Uzay kısıtlaması ekledim.

2. adım: önde gelen alan kısıtlamaları ekleyin

3) Sonra, önde gelen alanın özelliklerini değiştirdim, böylece sabit 0 ve çarpan, x ofseti ekranın genişliğine bölünür (örn. İlk düğmem sol kenardan 8 piksel idi, bu yüzden çarpanımı 8/320'ye ayarladım)

4) O zaman buradaki önemli adım, kısıtlama ilişkisindeki ikinci Öğeyi, denetim.kurşun yerine denetleme olarak değiştirmek. Bu önemlidir çünkü denetim. 0 ve benim durumumda iz sürmek 320, yani 8/320 320 piksel bir cihazda 8 piksel, daha sonra denetimin genişliği 640 ya da her neyse, görünümler genişliğe göre bir oranda hareket eder 320 piksel ekran boyutunda. Buradaki matematiği anlamak çok daha basit.

adım 3 ve 4: çarpanı xPos / screenWidth olarak değiştirin ve ikinci öğeyi .Trailing olarak ayarlayın


2

Birçok cevap doğru değil, ama çok sayım alıyor. Burada sadece programlı bir çözüm yazıyorum, üç görünüm, boşluk görünümleri kullanmadan yatay hizalamadır , ancak yalnızca etiket genişlikleri film şeridinde kullanıldığında bilinir .

NSDictionary *views = NSDictionaryOfVariableBindings(_redView, _yellowView, _blueView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_redView(60)]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:0.5 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_blueView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:1.5 constant:40]];

2

İşte başka bir cevap daha. Benzer bir soruyu yanıtlıyordum ve bu soruya atıfta bulunulan bağlantıyı gördüm. Benimkine benzer bir cevap görmedim. Ben de buraya yazmayı düşündüm.

  class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.whiteColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        view.addSubview(container1)
        view.addSubview(container2)
        view.addSubview(container3)
        view.addSubview(container4)

        [

            // left right alignment
            container1.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            container1.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20),
            container2.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container2.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container3.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container3.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container4.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container4.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),


            // place containers one after another vertically
            container1.topAnchor.constraintEqualToAnchor(view.topAnchor),
            container2.topAnchor.constraintEqualToAnchor(container1.bottomAnchor),
            container3.topAnchor.constraintEqualToAnchor(container2.bottomAnchor),
            container4.topAnchor.constraintEqualToAnchor(container3.bottomAnchor),
            container4.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),


            // container height constraints
            container2.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container3.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container4.heightAnchor.constraintEqualToAnchor(container1.heightAnchor)
            ]
            .forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false

        let button = UIButton(type: .System)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(title, forState: .Normal)
        view.addSubview(button)

        [button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
            button.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
            button.rightAnchor.constraintEqualToAnchor(view.rightAnchor)].forEach { $0.active = true }

        return view
    }
}

resim açıklamasını buraya girin

Ve yine, bu iOS9 UIStackViews ile de oldukça kolay bir şekilde yapılabilir.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.greenColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        let stackView = UIStackView(arrangedSubviews: [container1, container2, container3, container4])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .Vertical
        stackView.distribution = .FillEqually
        view.addSubview(stackView)

        [stackView.topAnchor.constraintEqualToAnchor(view.topAnchor),
            stackView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
            stackView.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            stackView.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20)].forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let button = UIButton(type: .Custom)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.redColor()
        button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        button.setTitle(title, forState: .Normal)
        let buttonContainer = UIStackView(arrangedSubviews: [button])
        buttonContainer.distribution = .EqualCentering
        buttonContainer.alignment = .Center
        buttonContainer.translatesAutoresizingMaskIntoConstraints = false
        return buttonContainer
    }
}

Yukarıdakiyle aynı yaklaşım olduğuna dikkat edin. Eşit olarak doldurulmuş dört kap görünümü ekler ve her bir yığın görünümüne, ortada hizalanmış bir görünüm eklenir. Ancak, bu UIStackView sürümü bazı kodları azaltır ve güzel görünür.


1

Başka bir yaklaşım, üst ve alt etiketlerin sırasıyla görüntünün üst ve alt kısmına göre kısıtlamalara sahip olması ve orta görünümün sırasıyla birinci ve üçüncü görünüme göre üst ve alt kısıtlamalara sahip olması olabilir.

Kesik çizgiler üzerinde kılavuz çizgileri görünene kadar birbirine yakın sürükleyerek göründüğünüzden daha fazla kontrole sahip olduğunuzu unutmayın - bunlar nesne ve denetim arasında oluşturulacak iki nesne arasındaki kısıtlamaları gösterir.

Bu durumda, kısıtlamaları, yeniden boyutlandırmalarını sağlamak için "eşit" yerine, istenen değerden "büyük veya eşit" olarak değiştirmek istersiniz. Bunun tam olarak ne istediğinizi yapacağından emin değilim.


1

InterfaceBuilder'da bunu çözmenin çok kolay yolu:

Ortalanmış etiketi (etiket2) "Kapta Yatay Merkez" ve "Kapta Dikey Merkez" olarak ayarlayın

Ortalanmış etiketi ve üst etiketi (etiket1 + etiket2) seçin ve Dikey Aralık için İKİ sınırlama ekleyin . Bir ile denk veya daha fazla dk aralığı. Bir ile eşit veya daha düşük maksimum aralık.

Ortalanmış etiket ve alt etiket için aynıdır (etiket2 + etiket3).

Ek olarak, label1'e iki sınırlama ve SuperView'a Üst Boşluk ve label2'ye iki kısıtlama - SuperView'e Alt Boşluk ekleyebilirsiniz.

Sonuç olarak, 4 aralığın tümü boyutlarını eşit olarak değiştirecektir.


2
Bu sadece denetim yeniden boyutlandırmak zaman aralığı tam olarak min veya max değerleri alır çalıştığını bulundu. Aradaki bir değerde yeniden boyutlandırdığınızda, alt görünümler eşit olarak dağıtılmaz.
Dorian Roy

1

Yardımcı olabilecek bir işlev yaptım. Bu kullanım örneği:

 [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                asString:@[@"button1", @"button2", @"button3"]
                                                               alignAxis:@"V"
                                                          verticalMargin:100
                                                        horizontalMargin:50
                                                             innerMargin:25]];

bu dikey dağılıma neden olur (üzgünüm görüntüleri gömmek için 10 üne sahip değilsiniz). Ekseni ve bazı kenar boşluğu değerlerini değiştirirseniz:

alignAxis:@"H"
verticalMargin:120
horizontalMargin:20
innerMargin:10

Anlayacaksın yatay dağılımı .

İOS'ta yeniyim ama voilà!

EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of subviews
 * to be evenly distributed along an axis.
 */
+ (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                               asString:(NSArray *) stringViews
                              alignAxis:(NSString *) axis
                         verticalMargin:(NSUInteger) vMargin
                       horizontalMargin:(NSUInteger) hMargin
                            innerMargin:(NSUInteger) inner;
@end

EvenDistribution.m

#import "EvenDistribution.h"

@implementation NSLayoutConstraint (EvenDistribution)

+ (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                              asString:(NSArray *) stringViews
                             alignAxis:(NSString *) axis
                        verticalMargin:(NSUInteger) vMargin
                      horizontalMargin:(NSUInteger) hMargin
                           innerMargin:(NSUInteger) iMargin

{
    NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
    NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                     axis,
                                     [axis isEqualToString:@"V"] ? vMargin : hMargin
                                     ];



        for (NSUInteger i = 0; i < dictViews.count; i++) {

            if (i == 0)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
            else if(i == dictViews.count - 1)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
            else
               [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];

            NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                     [axis isEqualToString:@"V"] ? @"H" : @"V",
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                     stringViews[i],
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin];

            [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:dictViews]];


    }
    [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                [axis isEqualToString:@"V"] ? vMargin : hMargin
                                ]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                             options:0
                                                                             metrics:nil
                                                                               views:dictViews]];

    return constraints;

}

@end

1

Evet, bunu yalnızca arayüz oluşturucuda ve kod yazmadan yapabilirsiniz - bir uyarı, boşluk dağıtmak yerine etiketi yeniden boyutlandırmanızdır. Bu durumda, Etiket 2'nin X ve Y'yi merkeze sabitlenecek şekilde süpervizeyle hizalayın. Ardından, etiket 1'in dikey boşluğunu denetime ve etiket 2'yi standarda göre ayarlayın, etiket 3 için tekrarlayın. Etiket 2'yi ayarladıktan sonra, etiket 1 ve 3'ü ayarlamanın en kolay yolu, onları yerine oturana kadar yeniden boyutlandırmaktır.

İşte yatay ekran, etiket 1 ve 2 arasındaki dikey boşluğun standart olarak ayarlandığını unutmayın:yatay ekran

Ve işte portre versiyonu:resim açıklamasını buraya girin

Etiketler arasındaki standart alan ile denetim için standart alan arasındaki farktan dolayı, taban çizgileri arasında kesinlikle% 100 eşit aralıklı olmadıklarının farkındayım. Bu sizi rahatsız ediyorsa, boyutu standart yerine 0 olarak ayarlayın


1

Yalnızca ilk öğe için genişlik değeri (> = genişlik) ve her öğe arasında minimum mesafe (> = mesafe) ayarlıyorum. Sonra Ctrl kullanarak ikinci, üçüncü ... öğe öğeleri arasında bağımlılıkları zincir için sürükleyin.

resim açıklamasını buraya girin


1

Partiye geç ama boşluklu yatay bir menü oluşturmak için çalışan bir çözüm var. ==NSLayoutConstraint ile kolayca yapılabilir

const float MENU_HEIGHT = 40;

- (UIView*) createMenuWithLabels: (NSArray *) labels
    // labels is NSArray of NSString
    UIView * backgroundView = [[UIView alloc]init];
    backgroundView.translatesAutoresizingMaskIntoConstraints = false;

    NSMutableDictionary * views = [[NSMutableDictionary alloc] init];
    NSMutableString * format = [[NSMutableString alloc] initWithString: @"H:|"];
    NSString * firstLabelKey;

    for(NSString * str in labels)
    {
        UILabel * label = [[UILabel alloc] init];
        label.translatesAutoresizingMaskIntoConstraints = false;
        label.text = str;
        label.textAlignment = NSTextAlignmentCenter;
        label.textColor = [UIColor whiteColor];
        [backgroundView addSubview: label];
        [label fixHeightToTopBounds: MENU_HEIGHT-2];
        [backgroundView addConstraints: [label fixHeightToTopBounds: MENU_HEIGHT]];
        NSString * key = [self camelCaseFromString: str];
        [views setObject: label forKey: key];
        if(firstLabelKey == nil)
        {
            [format appendString: [NSString stringWithFormat: @"[%@]", key]];
            firstLabelKey = key;
        }
        else
        {
            [format appendString: [NSString stringWithFormat: @"[%@(==%@)]", key, firstLabelKey]];
        }
    }

    [format appendString: @"|"];

    NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat: (NSString *) format
                                                                               options: 0
                                                                               metrics: nil
                                                                                 views: (NSDictionary *) views];
    [backgroundView addConstraints: constraints];
    return backgroundView;
}

0

Android, taklit etmek istediğim kısıtlama tabanlı düzen sisteminde görünümleri bir araya getirme yöntemine sahiptir. Aramalar beni buraya getirdi ama cevapların hiçbiri işe yaramadı. StackViews kullanmak istemiyorlardı çünkü onlar bana ön kaydettiklerinden daha fazla keder neden eğilimindedir. Görünümler arasında yer alan UILayoutGuides kullanılan bir çözüm oluşturdu. Genişliklerini kontrol etmek, Android dağıtımında farklı dağıtım türlerine, zincir stillerine izin verir. İşlev, üst görünüm yerine öndeki ve sondaki bağlantı noktalarını kabul eder. Bu, zincirin üst görünümün içine dağıtılmak yerine iki rastgele görünüm arasına yerleştirilmesini sağlar. Bu kullanımını yapar UILayoutGuideiOS'ta kullanılabilir 9+ ama bu artık sorun olmamalı.

public enum LayoutConstraintChainStyle {
    case spread //Evenly distribute between the anchors
    case spreadInside //Pin the first & last views to the sides and then evenly distribute
    case packed //The views have a set space but are centered between the anchors.
}

public extension NSLayoutConstraint {

    static func chainHorizontally(views: [UIView],
                                  leadingAnchor: NSLayoutXAxisAnchor,
                                  trailingAnchor: NSLayoutXAxisAnchor,
                                  spacing: CGFloat = 0.0,
                                  style: LayoutConstraintChainStyle = .spread) -> [NSLayoutConstraint] {
    var constraints = [NSLayoutConstraint]()
    guard views.count > 1 else { return constraints }
    guard let first = views.first, let last = views.last, let superview = first.superview else { return constraints }

    //Setup the chain of views
    var distributionGuides = [UILayoutGuide]()
    var previous = first
    let firstGuide = UILayoutGuide()
    superview.addLayoutGuide(firstGuide)
    distributionGuides.append(firstGuide)
    firstGuide.identifier = "ChainDistribution\(distributionGuides.count)"
    constraints.append(firstGuide.leadingAnchor.constraint(equalTo: leadingAnchor))
    constraints.append(first.leadingAnchor.constraint(equalTo: firstGuide.trailingAnchor, constant: spacing))
    views.dropFirst().forEach { view in
        let g = UILayoutGuide()
        superview.addLayoutGuide(g)
        distributionGuides.append(g)
        g.identifier = "ChainDistribution\(distributionGuides.count)"
        constraints.append(contentsOf: [
            g.leadingAnchor.constraint(equalTo: previous.trailingAnchor),
            view.leadingAnchor.constraint(equalTo: g.trailingAnchor)
        ])
        previous = view
    }
    let lastGuide = UILayoutGuide()
    superview.addLayoutGuide(lastGuide)
    constraints.append(contentsOf: [lastGuide.leadingAnchor.constraint(equalTo: last.trailingAnchor),
                                    lastGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
    distributionGuides.append(lastGuide)

    //Space the according to the style.
    switch style {
    case .packed:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalTo: first.widthAnchor))
            constraints.append(contentsOf:
                distributionGuides.dropFirst().dropLast()
                    .map { $0.widthAnchor.constraint(equalToConstant: spacing) }
                )
        }
    case .spread:
        if let first = distributionGuides.first {
            constraints.append(contentsOf:
                distributionGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: first.widthAnchor) })
        }
    case .spreadInside:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(equalToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalToConstant: spacing))
            let innerGuides = distributionGuides.dropFirst().dropLast()
            if let key = innerGuides.first {
                constraints.append(contentsOf:
                    innerGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: key.widthAnchor) }
                )
            }
        }
    }

    return constraints
}

0

5 görüntüyü yatay olarak hizalamak istedim, bu yüzden Mete'nin yanıtını takip ettim küçük bir farkla .

İlk görüntü yatay olarak 0'a eşit ve 1: 5 çarpanına ortalanır:

ilk görüntü

İkinci görüntü yatay olarak 0'a eşit ve 3: 5 çarpanına ortalanır: ikinci resim

Ve diğer görüntüler için böyle. Örneğin, beşinci (ve son) görüntü, 0'a eşit bir kapta ve 9: 5'in bir çarpanında yatay olarak ortalanır: son görüntü

Mete'nin açıkladığı gibi, düzen 1, 3, 5, 7, 9 vb. Gider. Konumlar aynı mantığı takip eder: ilk konum 1, sonra boşluk, sonra bir sonraki konum 3 vb.


-1

Neden sadece bir tablo oluşturmuyorsun? isScrollEnabled = false


Downvote anlamıyorum, benim çözüm kutunun dışında düşünmek. Kakao size UITableView'da bir liste verdiğinde neden otomatik listeyle bir liste oluşturmanın başını çekiyorsunuz?
Josh O'Connor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.