Dolgu a UILabel
, tam çözüm. 2020 için güncellendi.
O orada çıkıyor üç şey yapılmalıdır.
1. textRect # forBounds öğesini yeni küçük boyuta çağırmalısınız
2. Yeni küçük boyutta drawText'i geçersiz kılmalı
3. Dinamik olarak boyutlandırılmış bir hücre, intrinsicContentSize ayarlamalıdır
Aşağıdaki tipik örnekte, metin birimi tablo görünümünde, yığın görünümünde veya benzer bir yapıdadır, bu da ona sabit bir genişlik verir . Örnekte 60,20,20,24 dolgu istiyoruz.
Böylece, "varolan" intrinsicContentSize almak ve aslında yüksekliğe 80 ekleyin .
Tekrarlamak için ...
Kelimenin tam anlamıyla, motor tarafından "şimdiye kadar hesaplanan yüksekliği" almanız ve bu değeri değiştirmeniz gerekir .
Bu süreci kafa karıştırıcı buluyorum, ama işte böyle çalışıyor. Benim için Apple, "ön yükseklik hesaplaması" gibi bir şeyi açığa çıkarmalıdır.
İkinci olarak, textRect # forBounds çağrısını yeni küçük boyutumuzla kullanmamız gerekiyor .
TextRect # forBounds'da, önce boyutu küçültür ve sonra süper çağırırız.
Uyarmak! Sen gerekir süper çağrı sonrasında , daha önce değil!
Bu sayfadaki tüm girişimleri ve tartışmaları dikkatlice araştırırsanız, sorun tam olarak budur. Bazı çözümlerin "neredeyse işe yaradığına" dikkat edin, ancak birileri belirli durumlarda işe yaramayacağını bildirecektir. Bu gerçekten de kesin neden - kafa karıştırıcı bir şekilde, daha sonra değil, “sonradan süper aramalısınız”.
Bu nedenle, süper "yanlış sırada" olarak adlandırılırsa, genellikle çalışır, ancak belirli metin uzunlukları için geçerli değildir .
"Yanlış süper yapmak" için tam bir görsel örnek:
60,20,20,24 kenar boşluklarının doğru olduğuna dikkat edin.
Sabit:
TextRect # forBounds motorunun yalnızca şimdi hesaplamanın nasıl düzgün bir şekilde yapılacağını bildiğine dikkat edin :
En sonunda!
Yine, bu örnekte UILabel, genişliğin sabitlendiği tipik durumda kullanılmaktadır. Yani intrinsicContentSize içinde istediğimiz toplam ekstra yüksekliği "eklememiz" gerekir. (Genişliğe herhangi bir şekilde "eklemeniz" gerekmez, bu sabit olduğu için anlamsızdır.)
Daha sonra textRect # forBounds'ta, autolayout tarafından "şimdiye kadar önerilen" sınırlarını alırsınız, kenar boşluklarınızı çıkarırsınız ve ancak daha sonra textRect # forBounds motoruna tekrar çağırabilirsiniz, bu da size bir sonuç verir.
Son olarak ve drawText'te elbette aynı küçük kutuda çizin.
Uf!
let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired
override var intrinsicContentSize:CGSize {
numberOfLines = 0 // don't forget!
var s = super.intrinsicContentSize
s.height = s.height + UIEI.top + UIEI.bottom
s.width = s.width + UIEI.left + UIEI.right
return s
}
override func drawText(in rect:CGRect) {
let r = rect.inset(by: UIEI)
super.drawText(in: r)
}
override func textRect(forBounds bounds:CGRect,
limitedToNumberOfLines n:Int) -> CGRect {
let b = bounds
let tr = b.inset(by: UIEI)
let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
// that line of code MUST be LAST in this function, NOT first
return ctr
}
Bir kere daha. Bu ve "neredeyse" doğru olan diğer KG'deki cevapların yukarıdaki ilk görüntüde sorun yaşadığını unutmayın - "süper yanlış yerdedir" . İntrinsicContentSize içinde boyutu daha büyük zorlamalısınız ve daha sonra textRect # forBounds'ta önce ilk öneri sınırlarını küçültmeli ve sonra süper çağırmalısınız.
Özet: textRect # forBounds içinde " süper son çağır" gerekir
Bu sır.
Ayrıca geçersiz kılmayı, sizeThatFits, needsLayout veya başka bir zorlama çağrısını çağırmanız gerekmediğini ve buna gerek olmadığını unutmayın. Doğru otomatik çözüm, normal otomatik yerleşim çekme döngüsünde düzgün çalışmalıdır.
İpucu:
Tek aralıklı yazı tipleriyle çalışıyorsanız, harika bir ipucu: https://stackoverflow.com/a/59813420/294884