iOS: Otomatik Mizanpajda çok satırlı UILabel


183

Otomatik Düzen ile bazı çok temel düzen davranışlarına ulaşmaya çalışırken sorun yaşıyorum. Görünüm denetleyicim IB'de şöyle görünüyor:

resim açıklamasını buraya girin

Üst etiket başlık etiketidir, kaç satır olacağını bilmiyorum. Tüm metin satırlarını görüntülemek için başlık etiketine ihtiyacım var. Ayrıca diğer iki etikete ve küçük resmin başlığın hemen altına yerleştirilmesine ihtiyacım var, ancak ne kadar uzun olursa olsun. Etiketler ve küçük resim arasındaki dikey boşluk sınırlamalarının yanı sıra başlık etiketi ve denetimi arasında bir üst boşluk kısıtlaması ve küçük resim ile denetimi arasında bir alt boşluk kısıtlaması ayarladım. Beyaz UIView'in yükseklik kısıtlaması yoktur, bu nedenle alt görünümlerini içerecek şekilde dikey olarak uzanmalıdır. Başlık etiketi için satır sayısını 0 olarak ayarladım.

Dizenin gerektirdiği satır sayısına sığması için başlık etiketinin yeniden boyutlandırılmasını nasıl sağlayabilirim? Anladığım kadarıyla, Auto Layout kullanıyorum çünkü setFrame yöntemlerini kullanamıyorum. Başlık etiketinin altında kalmak için diğer görünümlere ihtiyacım olduğu için Otomatik Düzen'i kullanmak zorundayım (dolayısıyla kısıtlamalar).

Bunu nasıl yapabilirim?


3
Ben de benzer bir problemle savaşıyorum. Ama yine de, yüksekliğini içeriğe uyacak şekilde dinamik olarak ayarlaması için en iyi etiketi almaya çalışıyorum. Bunu nasıl başardınız?
jbandi

1
Lütfen @ mwhuss'un cevabını kabul edilen olarak işaretleyin.
jemmons

1
Gerekli sonucu elde ettiniz mi?
Aniruddha

Bunu kontrol edin, tek satır kod eklemenize gerek yoktur stackoverflow.com/a/36862795/4910767
Badal Shah

Yanıtlar:


254

Kullanım -setPreferredMaxLayoutWidthüzerindeki UILabeldinlenme işlemesi gerektiğini ve Otomatik mizanpaj.

[label setPreferredMaxLayoutWidth:200.0];

Tercih edilen MaxLayoutWidth ile ilgili UILabel belgelerine bakın .

Güncelleme:

Yalnızca heightfilm şeridindeki kısıtlamayı ayarlamanız Greater than or equal togerekir, PreferredMaxLayoutWidth öğesini ayarlamanıza gerek yoktur.


8
Güzel, yine de bunu arayüz oluşturucuda yapmak için?
Sjoerd Perfors

12
Ayrıca, IB'deki yükseklik sınırlamasını "eşit veya daha büyük" olarak ayarlayın.
jowie

10
Hatırlatma: Lütfen numberOfLines özelliğini ayarlamayı unutmayın.
Li Fumin

2
Evet, maksimum genişliğin olmasını istediğiniz her şeyi kullanın.
mwhuss

4
Bkz stackoverflow.com/a/29180323/1529675 nasıl belirleneceği için preferredMaxLayoutWidthve bakın devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html , ile tam bir kısa ama bilgilendirici writeup için animasyonlu GIF'ler (benim
yazım

213

Etiket kümesi satır sayısını 0'a, ayrıca otomatik düzen ayarı yüksekliğini> = x olarak genişletin. Otomatik düzen gerisini halleder. Daha sonra doğru konumlandırmak için önceki öğeye dayalı diğer öğelerinizi de içerebilir.

otomatik düzen


Bu yöntem sizin için işe yaramazsa, lütfen Cory Imdieke'nin sonraki görünümlerin Otomatik Düzen'in (muhtemelen) çok satırlı görünümü yeniden boyutlandırmasını engellemediğinden emin olma konusundaki cevabına bakın.
Tom Howard

1
Tablo Görünümü Hücresi içinde benim için çalışan tek cevap bu. Ayrıca sabit sayıda satırla çalışır (0 / sınırsız yerine)
bgolson

Bu benim için açık bir tercih edilen maksimum genişlik ayarlı olarak çalışmadı, bu nedenle bu tekniği kullanırken bunun IB'de otomatik olarak ayarlandığından emin olun. Şerefe
jmc

Otomatik maksimum genişliği ayarlama yalnızca iOS8'de kullanılabilir. Ayrıca, benim anlayışımdan, yüksekliği otomatik olarak ayarlayacaktır ve deneyimlerime göre çalışması için bir yükseklik sınırlaması ayarlamanıza gerek yoktur. Bu benim için açık bir genişlik kullanarak işe yaradı.
Tony

1
Bu benim için işe yaramadı. Ben stackoverflow.com/a/13032251/1529675 doğru yanıt olduğuna inanıyorum .
tboyce12

48

Kaynak: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Çok Satırlı Metnin İç İçerik Boyutu

UILabel ve NSTextField öğelerinin gerçek içerik boyutu çok satırlı metin için belirsizdir. Metnin yüksekliği, sınırlamalar çözülürken henüz belirlenmemiş olan çizgilerin genişliğine bağlıdır. Bu sorunu çözmek için, her iki sınıfın da içsel içerik boyutunu hesaplamak için maksimum satır genişliğini belirten preferMaxLayoutWidth adlı yeni bir özelliği vardır.

Genellikle bu değeri önceden bilmediğimizden, bunu doğru yapmak için iki adımlı bir yaklaşım benimsememiz gerekir. İlk önce Otomatik Mizanpaj'ın işini yapmasına izin veriyoruz ve sonra tercih edilen maksimum genişliği ve tetikleme düzenini tekrar güncellemek için düzen geçişinde ortaya çıkan çerçeveyi kullanıyoruz.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Etiketin çerçeve kümesini alması için ilk [super layoutSubviews] çağrısı, değişiklikten sonra düzeni güncellemek için ikinci çağrı gereklidir. İkinci çağrıyı atlarsak NSInternalInconsistencyException hatası alırız, çünkü düzen geçişinde kısıtlamaların güncellenmesini gerektiren değişiklikler yaptık, ancak düzeni tekrar tetiklemedik.

Bunu bir etiket alt sınıfında da yapabiliriz:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

Bu durumda, önce [super layoutSubviews] öğesini çağırmamız gerekmez, çünkü layoutSubviews çağrıldığında, etiketin kendisinde zaten bir çerçevemiz vardır.

Bu ayarlamayı görünüm denetleyicisi düzeyinden yapmak için viewDidLayoutSubviews'e bağlanırız. Bu noktada, ilk Otomatik Mizanpaj geçişinin çerçeveleri zaten ayarlanmıştır ve bunları tercih edilen maksimum genişliği ayarlamak için kullanabiliriz.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Son olarak, etiket üzerinde, etiketin içerik sıkıştırma direnci önceliğinden daha yüksek önceliği olan açık bir yükseklik kısıtlamanız olmadığından emin olun. Aksi takdirde, içeriğin hesaplanan yüksekliğini keser. Etiketin yüksekliğini etkileyebilecek tüm kısıtlamaları kontrol ettiğinizden emin olun.


teşekkür ederim teşekkür ederim sadece kod için değil, daha da önemlisi, bunun bir alt sınıfta değil, aynı zamanda görünüm denetleyicisinden de nasıl yapılacağına dair açıklama ve örnekler için teşekkür ederim.
djibouti33

görünüm denetleyicimde bunu deniyorum ve viewDidLayoutSubviews viewWillAppear ve viewDidAppear sonra çağrılıyor. ViewDidAppear'dan sonra, etiketler doğru şekilde yeniden boyutlandırıldığında bir flaş olur. Bundan kaçınmamın bir yolu var mı? kullanıcı herhangi bir şey görmeden önce yeniden boyutlandırmak için bir yolu var mı? benim durumumda, çok satırlı etiketlerim bir tableHeaderView'da ve bu yüzden de bu örneği kullanarak başlık görünümünün yüksekliğini yeniden boyutlandırıyorum ( stackoverflow.com/questions/20982558/… )
djibouti33

@ djibouti33 sorununuzu kolayca kontrol edebilmem için lütfen minimum örnek kodu (örn. github repo formatında) verebilir misiniz?
Anton Matosov

Teşekkürler @Anton. Tasarımımız o zamandan beri bir UITableView'dan UICollectionView'a geçti ve neyse ki bu davranışı görmedim. Git geçmişime küçük bir örnek proje oluşturmak için ulaşabilirsem, size bildiririm.
djibouti33

Bir iOS 9 sim üzerinde çalışmaya başladığımdan beri benim için bir sorun ama iOS 8'de test ettiğimde sorun başladı. Maksimum genişliği manuel olarak ayarlamam gerekiyor.
naz

17

Ben sadece bu senaryo ile savaşıyordum, ama gerektiğinde yeniden boyutlandırmak ve aşağı inmek için gereken birkaç görüşle. Beni deli ediyordu, ama sonunda anladım.

İşte önemli nokta: Interface Builder, görünümler ekledikçe ve taşıdıkça ekstra kısıtlamalar atmayı sever ve fark etmeyebilirsiniz. Benim durumumda, yarısı ile onun denetimi arasındaki boyutu belirten ekstra bir kısıtlamaya sahip, temelde o noktaya sabitleyen bir görüşüm vardı. Bu, yukarıdaki hiçbir şeyin daha büyük bir boyutta yeniden boyutlandırılamayacağı anlamına geliyordu, çünkü bu kısıtlamaya karşı gidecekti.

Durumun bu olup olmadığını anlamanın kolay bir yolu, etiketi manuel olarak yeniden boyutlandırmaya çalışmaktır. IB onu büyütmene izin veriyor mu? Varsa, aşağıdaki etiketler beklediğiniz gibi mi hareket ediyor? Kısıtlamalarınızın görünümlerinizi nasıl taşıyacağını görmek için yeniden boyutlandırmadan önce ikisini de işaretlediğinizden emin olun:

IB Menüsü

Görünüm sıkışmışsa, altındaki görünümleri izleyin ve bunlardan birinin kısıtlamayı denetlemek için en üst alana sahip olmadığından emin olun. Ardından, etiket için satır sayısı seçeneğinizin 0 olarak ayarlandığından emin olun ve geri kalanıyla ilgilenmelidir.


Evet, onunla çok oynadıktan sonra istediğim etkiyi elde edebildim. Sadece istediğiniz kısıtlamalar hakkında çok dikkatli düşünmelisiniz. IB'nin sürekli beklemediğiniz kısıtlamaları atmasına yardımcı olmaz.
James Harpe

5

Aşağıdakilere ihtiyacınız olduğunu düşünüyorum:

  • En büyük kısıtlama
  • Önde gelen bir kısıtlama (örn. Sol taraf)
  • Sondaki bir kısıtlama (örn. Sağ taraf)
  • İçeriği sarma önceliğini yataydan alçaka ayarlayın, böylece metin kısasa verilen alanı dolduracaktır.
  • İçerik sıkıştırma direncini yataydan alçaka ayarlayın, böylece daha geniş olmaya çalışmak yerine sarın.
  • Satır sayısını 0 olarak ayarlayın.
  • Satır sonu modunu sözcük kaydırmaya ayarlayın.

Bu, xcode9'da çalışmalıdır. Etiket yüksekliği kısıtlamasıyla hiçbir şey yapmak zorunda kalmadım (hiç yok): etiket kısıtlandıktan sonra (sondaki, önde, üst ve alt) sadece kutudan çıkar. Uikit gerisini yapıyor
Anton Tropashko

İçerik sarılma önceliği benim sorunumdu. Sıkıştırma direncinin yanı sıra bu özellik hakkında beni bilgilendirdiğiniz için teşekkür ederiz. Saatlerce süren bir sorunu çözmeme yardım ettin.
David Gay

0

Konuyla ilgili birçok konuda bulunan farklı çözümlerin hiçbiri benim durumum için mükemmel çalışmadı (dinamik tablo görünümü hücrelerinde x dinamik çok satırlı etiketler).

Bunu yapmanın bir yolunu buldum:

Etiketinizdeki kısıtlamaları ayarladıktan ve çok satırlı özelliğini 0 olarak ayarladıktan sonra, bir UILabel alt sınıfı yapın; Benim AutoLayoutLabel'i aradım:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end

0

Metin sarma etiketi olan bir UITableViewCell var. Metin sarma çalıştım aşağıdaki gibi.

1) UILabel kısıtlamalarını aşağıdaki gibi ayarlayın.

resim açıklamasını buraya girin

2) Ayar no. 0 olarak satır.

3) UITableViewCell'e UILabel yükseklik kısıtlaması eklendi.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) UITableViewCell'de:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

-12

Bunu yapmanın bir yolu ... Metin uzunluğu arttıkça, etiket metninin yazı tipini kullanarak

Label.adjustsFontSizeToFitWidth = YES;

1
Görünüm denetleyicisinin farklı örneklerinin tutarlı bir görünüme sahip olmasını istiyorum, bu nedenle yazı tipi boyutunu değiştirmek istemiyorum.
James Harpe
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.