Otomatik Yerleşimli Kendinden Boyutlu Hücreler


207

UICollectionViewCellsOtomatik Düzenleme ile kendiliğinden boyutlandırma yapmaya çalışıyorum , ancak hücrelerin kendilerini içeriğe boyutlandırmasını sağlayamıyorum. Hücrenin boyutunun, hücrenin contentView içindeki içeriğinden nasıl güncellendiğini anlamada sorun yaşıyorum.

İşte denedim kurulum:

  • Özel UICollectionViewCellbir ile UITextViewonun contentView içinde.
  • İçin kaydırma UITextViewdevre dışı bırakıldı.
  • ContentView'ın yatay kısıtlaması: "H: | [_textView (320)]", yani UITextViewhücre 320'nin açık genişliği ile hücrenin soluna sabitlenir.
  • ContentView'in dikey kısıtlaması: "V: | -0 - [_ textView]", yani UITextViewhücrenin üst kısmına sabitlenir.
  • UITextViewBir sabit ayarlanmış bir yükseklik kısıtlaması vardır UITextViewraporlar metni uyacaktır.

Hücre arka planı kırmızıya ve UITextViewarka plan Mavi olarak ayarlandığında şöyle görünür : hücre arka planı kırmızı, UITextView arka plan mavi

Oynadığım projeyi GitHub'a buraya koydum .


SizeForItemAtIndexPath yöntemini uyguluyor musunuz?
Daniel Galasko

@DanielGalasko Değilim. Anladığım kadarıyla, iOS 8'deki yeni kendi kendine boyutlandırma hücreleri özelliği, artık bunu yapmanızı gerektirmiyor.
rawbee

Bu bilgiyi nereden aldığınızdan emin değilsiniz, ancak hala ihtiyacınız var, WWDC alıntısına bir göz atın asciiwwdc.com/2014/sessions/226
Daniel Galasko

ama yine de sizin kullanım durumunuza bağlıdır,
tahminiItemSize

1
2019 - Şuna bakmak çok önemli: stackoverflow.com/a/58108897/294884
Fattie

Yanıtlar:


309

Swift 5 için güncellendi

preferredLayoutAttributesFittingAttributespreferredLayoutAttributesFittingotomatik boyutlandırma olarak yeniden adlandırıldı ve kullan


Swift 4 için güncellendi

systemLayoutSizeFittingSize olarak yeniden adlandırıldı systemLayoutSizeFitting


İOS 9 için güncellendi

GitHub çözümünün iOS 9 altında kırıldığını gördükten sonra nihayet sorunu tam olarak araştırmak için zaman buldum. Kendini boyutlandırma hücreleri için farklı yapılandırmaların birkaç örneğini içerecek şekilde repo'yu güncelledim. Benim sonucum, kendiliğinden boyutlanan hücrelerin teoride büyük, ancak pratikte dağınık olmasıdır. Kendiliğinden boyutlanan hücrelerle devam ederken dikkat edilmesi gereken bir kelime.

TL; DR

GitHub projeme göz atın


Kendiliğinden boyutlanan hücreler yalnızca akış düzeniyle desteklenir, bu nedenle kullandığınızdan emin olun.

Kendiliğinden boyutlanan hücrelerin çalışması için ayarlamanız gereken iki şey vardır.

1. Set estimatedItemSizeüzerindeUICollectionViewFlowLayout

estimatedItemSizeÖzelliği ayarladıktan sonra akış düzeni doğada dinamik hale gelir .

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

2. Hücre alt sınıfınızda boyutlandırma desteği ekleyin

Bu 2 çeşittir; Otomatik Düzen veya özel geçersiz kılma preferredLayoutAttributesFittingAttributes.

Otomatik Düzen ile hücre oluşturma ve yapılandırma

Bir hücre için kısıtlamaları yapılandırma hakkında parlak bir SO yazı olduğu için bu konuda ayrıntılı olarak gitmeyeceğim . O Sadece dikkatli olun Xcode 6 kırdı iOS 7 destekleyen eğer iOS 7 öylesine şeyler bir demet, sen autoresizingMask hücrenin sınırları olduğu gibi ayarlanır contentView en sınırları hücrenin contentView üzerinde ve bu ayarlanır sağlamak gibi şeyler yapmanız gerekecektir hücre yüklenir (yani awakeFromNib).

Dikkat etmeniz gereken şeyler, hücrenizin bir Tablo Görüntüleme Hücresinden daha ciddi şekilde kısıtlanması gerektiğidir. Örneğin, genişliğinizin dinamik olmasını istiyorsanız, hücrenizin bir yükseklik sınırlaması olması gerekir. Benzer şekilde, yüksekliğin dinamik olmasını istiyorsanız, hücreniz için bir genişlik kısıtlamasına ihtiyacınız olacaktır.

Uygulamak preferredLayoutAttributesFittingAttributesözel hücrede

Bu işlev çağrıldığında, görünümünüz zaten içerikle yapılandırılmıştır (yani cellForItemçağrılmıştır). Kısıtlamalarınızın uygun şekilde ayarlandığını varsayarsak, bunun gibi bir uygulamaya sahip olabilirsiniz:

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    //Exhibit A - We need to cache our calculation to prevent a crash.
    if !isHeightCalculated {
        setNeedsLayout()
        layoutIfNeeded()
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = CGFloat(ceilf(Float(size.width)))
        layoutAttributes.frame = newFrame
        isHeightCalculated = true
    }
    return layoutAttributes
}

NOT iOS 9'da, dikkatli değilseniz davranış uygulamanızda çökmelere neden olabilecek bir miktar değişti (Daha fazla bilgi için buraya bakın ). Uyguladığınızda preferredLayoutAttributesFittingAttributes, düzen özelliklerinizin çerçevesini yalnızca bir kez değiştirdiğinizden emin olmanız gerekir. Bunu yapmazsanız, düzen süresiz olarak uygulamanızı çağırır ve sonunda çökecektir. Çözümlerden biri, hücrenizde hesaplanan boyutu önbelleğe almak ve hücreyi yeniden kullandığınızda veya isHeightCalculatedözelliği ile yaptığım gibi içeriğini değiştirdiğinizde bunu geçersiz kılmaktır .

Düzeninizi yaşayın

Bu noktada, collectionView öğenizde 'çalışan' dinamik hücreler olmalıdır. Testlerim sırasında kullanıma hazır çözümü henüz yeterli bulmadım, eğer varsa yorum yapmaktan çekinmeyin. Hala UITableViewdinamik boyutlandırma IMHO için savaşı kazanıyor gibi geliyor .

Uyarılar

TahminiItemSize değerini hesaplamak için prototip hücreler kullanıyorsanız, XIB'niz boyut sınıflarını kullanıyorsa bu durumun kırılacağına dikkat edin . Bunun nedeni, hücrenizi bir XIB'den yüklediğinizde boyut sınıfı ile yapılandırılacaktır Undefined. Bu yalnızca iOS 8 ve sonraki sürümlerde kesilecektir çünkü iOS 7'de boyut sınıfı cihaza göre yüklenecektir (iPad = Normal-Herhangi, iPhone = Kompakt-Herhangi). XIB'yi yüklemeden tahminiItemSize öğesini ayarlayabilir veya hücreyi XIB'den yükleyebilir, collectionView öğesine ekleyebilir (bu, traitCollection öğesini ayarlar), düzeni gerçekleştirebilir ve ardından denetimden kaldırabilirsiniz. Alternatif olarak, hücrenizi traitCollectionalıcıyı geçersiz kılabilir ve uygun özellikleri döndürebilirsiniz. Sana kalmış.

Bir şey kaçırırsam bana bildirin, yardım ettim ve iyi şanslar kodlama



2
Ben aynı şeyi akış düzeni ile uygulamaya çalışıyorum, ancak bunu güncellediğimizde newFrame ile, düzeni hala tahminSize yüksekliğe dayalı y pozisyonları yeniden hesaplamak gibi görünmüyor. Ne kayıp?
anna

@anna mizanpaj için geçersiz kılınıyor mu?
Daniel Galasko

1
Ah, farkı buldum, tahmin edilen yüksekliği oldukça yüksek olarak ayarladın (400). Bu yardımcı oldu. Ancak contentSize, siz bu şekilde ilerleyene kadar doğru ayarlanmıyor gibi görünüyor, bu yüzden hala çok kullanışlı değil. Btw, UITextView, UILabel, aynı davranış değiştirdim.
anna

17
Bu, iOS 9 GM'de temelde kırılmış gibi görünüyor. Ayar estimatedItemSizeçökmelere yol açar - otomatik düzenin UICollectionViewCell'i nasıl işlemeye çalıştığı konusunda büyük bir hata var gibi görünüyor.
Wes Campaigne

3
Benzer bir sorunla karşılaşırken, herhangi bir iş bulan var mı?
Tony,

47

İOS10'da UICollectionViewFlowLayout.automaticSize(eski adıyla UICollectionViewFlowLayoutAutomaticSize) yeni sabit var, bunun yerine:

self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)

bunu kullanabilirsiniz:

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

Özellikle toplama görünümünüzdeki hücreler sabit genişliğe sahip olduğunda daha iyi performans gösterir

Akış Düzenine Erişme:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
   }
}

Swift 5 Güncellendi:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
}

8
Bunu nereden ayarladın? viewdidload'da mı? Flowlayout ile nasıl başa çıkabilirsiniz?
UKDataGeek

1
Bunu uygulamayı başardım - ama tek bir hücre varsa hücrelerin ortalamasını sağlayan garip bir davranışı var. İşte bununla ilgili yığın taşması sorusu - beni
güdük

1
Akış düzenine collectionViews üzerinden erişebilir ve collectionViewLayoutbunun tür olup olmadığını kontrol edebilirsinizUICollectionViewFlowLayout
d4Rk

4
hücrelerimi çok küçük, işe yaramaz yapar
user924

44

Daniel Galasko'nun cevabındaki birkaç önemli değişiklik tüm sorunlarımı düzeltti. Ne yazık ki, doğrudan yorum yapmak için yeterli üne sahip değilim (henüz).

1. adımda, Otomatik Düzen'i kullanırken hücreye tek bir üst UIView ekleyin. Hücrenin içindeki HER ŞEY ebeveynin bir alt görünümü olmalıdır. Tüm sorunlarımı yanıtladı. Xcode bunu UITableViewCells için otomatik olarak eklese de, UICollectionViewCells için eklemez (ancak eklemelidir). Dokümanlara göre :

Hücrenizin görünümünü yapılandırmak için veri öğesinin içeriğini, contentView özelliğindeki görünüme alt görünüm olarak sunmak için gereken görünümleri ekleyin. Doğrudan hücrenin kendisine alt görünümler eklemeyin.

Ardından 3. adımı tamamen atlayın. Gerek yok.


1
İlginç; Bu özellikle Xibs için ama yine de teşekkürler, Github projesi ile uğraşmaya çalışacağım ve yeniden üretip üretemeyeceğimi göreceğim. Belki cevabı Xib'e programatik olarak ayırın
Daniel Galasko

Çok yararlı . Teşekkürler!
ProblemSlover

2
iOS 9, Xcode 7. Hücreler, storyboard'da, özel alt sınıfta ayarlanmış olarak prototiplenir. Adlı bir özellik oluşturmayı contentViewdeneyen Xcode, mevcut mülkle çakıştığından şikayet ediyor. Alt görünümler eklemeyi denedim self.contentViewve buna sınırlamalar koyduktan sonra uygulama kilitleniyor.
Nicolas Miari

@NicolasMiari Bunu programlı olarak nasıl yapacağımı bilmiyorum, benim çözümüm XIB'de her şeyin içine girdiği tek bir uiview eklemek. Bir mülk ya da başka bir şey oluşturmanız gerekmez.
Matt Koala

@NicolasMiari ile aynı sorunla karşı karşıyayım. İOS 9 / Xcode 7'de film şeridinde prototiplenmiş hücreler için tahminiContentSize değerini ayarladığımda, uygulama kötü erişim istisnası ve yararlı yığın izlemesi olmadan çöküyor
wasabi

34

İOS 10 ve sonraki sürümlerinde bu çok basit 2 adımlı bir işlemdir.

  1. Tüm hücre içeriğinizin tek bir UIView içine yerleştirildiğinden (veya otomatik yerleşimi çok kolaylaştıran UIStackView gibi bir UIView neslinin içine) yerleştirildiğinden emin olun. Tıpkı UITableViewCells'i dinamik olarak yeniden boyutlandırırken olduğu gibi, tüm görünüm hiyerarşisinin en dıştaki kaptan en iç görünüme kadar yapılandırılmış kısıtlamaları olması gerekir. Bu, UICollectionViewCell ve anında çocuk görünümü arasındaki kısıtlamaları içerir

  2. UICollectionView öğenizin akış düzenini otomatik olarak boyutlandırın

    yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

Merak ediyorum, hücrelerinizin içeriğini bir UIView içine sarmak Otomatik Mizanpaj'ın daha iyi performans göstermesini nasıl sağlayabilir? Daha sığ bir hiyerarşi ile daha iyi performans göstereceğini düşündüm mü?
James Heald

1
Performanstan bahsetmedim, sadece basitlik. Kendiliğinden boyutlanan hücreler, yalnızca sol ve sağ arasındaki ve üst ve alt arasındaki tüm sınırlara yayılmışsa çalışır. Tüm görünümler tek bir kapta sarıldığında bunu başarmak en kolay yoldur. Bu kap bir UIStackView ise, UIView'in başka bir torunu ise daha kolaydır.
Marmoy

Bana UICollectionViewFlowLayoutAutomaticSize için yükseklik sabitinin nasıl ayarlanacağını söyleyebilir misiniz (ayar yüksekliği 25 ve genişlik otomatik olarak değişecektir).
Svetoslav Atanasov

Swift 4.1 kullanarak Xcode bana UICollectionViewFlowLayout.automaticSizeyeniden adlandırıldığını söylüyor UICollectionViewFlowLayoutAutomaticSize.
LinusGeffarth

14
  1. ViewDidLoad () öğesine flowLayout ekle

    override func viewDidLoad() {
        super.viewDidLoad() 
        if let flowLayout = infoCollection.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = CGSize(width: 1, height:1)
        }
    }
  2. Ayrıca, hücreniz için mainContainer olarak bir UIView ayarlayın ve içine gerekli tüm görünümleri ekleyin.

  3. Daha fazla referans için bu harika, akıllara durgunluk veren eğiticiye başvurun: iOS 9 ve 10'da otomatik yerleşimi kullanan otomatik boyutlandırma hücresine sahip UICollectionView


11

EDIT 11/19/19: iOS 13 için, yalnızca UICollectionViewCompositionalLayout öğesini tahmini yüksekliklerle kullanın. Bu bozuk API ile uğraşarak zaman kaybetmeyin.

Bir süre bununla mücadele ettikten sonra, kaydırmayı devre dışı bırakmazsanız yeniden boyutlandırmanın UITextViews için çalışmadığını fark ettim:

let textView = UITextView()
textView.scrollEnabled = false

kaydırmaya çalıştığımda, koleksiyon görünümü hücresi düzgün değil. Bunun için bir çözümünüz var mı?
Sathish Kumar Gurunathan

6

ankraj gizemini görüntüle:

Tuhaf bir durumda bu

    contentView.translatesAutoresizingMaskIntoConstraints = false

işe yaramaz. ContentView'e dört açık bağlantı eklendi ve çalıştı.

class AnnoyingCell: UICollectionViewCell {
    
    @IBOutlet var word: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame); common() }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder); common() }
    
    private func common() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            contentView.leftAnchor.constraint(equalTo: leftAnchor),
            contentView.rightAnchor.constraint(equalTo: rightAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
}

ve her zamanki gibi

    estimatedItemSize = UICollectionViewFlowLayout.automaticSize

içinde YourLayout: UICollectionViewFlowLayout

Kim bilir? Birine yardım edebilir.

Kredi

https://www.vadimbulavin.com/collection-view-cells-self-sizing/

orada ipucu tökezledi - asla bu konuda tüm 1000s makalelerde başka bir yerde gördüm.


3

Koleksiyon görünümünde dinamik bir hücre yüksekliği yaptım. İşte git hub repo .

Ve tercihliLayoutAttributesFittingAttributes'ın neden birden çok kez çağrıldığını görün. Aslında, en az 3 kez çağrılacak.

Konsol günlüğü resmi: resim açıklamasını buraya girin

1. tercih edilenLayoutAttributesFittingAttributes :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c290e0> index path: (<NSIndexPath:    0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 57.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

LayoutAttributes.frame.size.height geçerli durum 57.5 .

2. tercih edilenLayoutAttributesFittingAttributes :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c16370> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

Hücre çerçeve yüksekliği beklediğimiz gibi 534.5 olarak değişti . Ancak, koleksiyon görünümü hala sıfır yüksekliktedir.

3. tercih edilenLayoutAttributesFittingAttributes :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa403d516a0> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 477);

Görebilirsiniz toplama görünümü yüksekliği 0 477 olarak değiştirildi .

Davranış, kaydırma tutamacına benzer:

1. Before self-sizing cell

2. Validated self-sizing cell again after other cells recalculated.

3. Did changed self-sizing cell

Başlangıçta, bu yöntemin sadece bir kez aradığını düşündüm. Bu yüzden aşağıdaki gibi kodladım:

CGRect frame = layoutAttributes.frame;
frame.size.height = frame.size.height + self.collectionView.contentSize.height;
UICollectionViewLayoutAttributes* newAttributes = [layoutAttributes copy];
newAttributes.frame = frame;
return newAttributes;

Bu hat:

frame.size.height = frame.size.height + self.collectionView.contentSize.height;

sistem çağrısı sonsuz döngü ve Uygulama kilitlenmesine neden olur.

Herhangi bir boyut değiştiğinde, her bir hücrenin konumu (yani kareler) artık değişiklik kalmayana kadar tüm hücrelerin tercih edilenLayoutAttributesFittingAttributes öğelerini tekrar tekrar doğrular.


2

Yukarıdaki cevaplara ek olarak,

Sadece emin olmak ayarladığınız estimatedItemSize malı UICollectionViewFlowLayout bazı boyutuna ve yok uygulamak sizeForItem: atIndexPath temsilci yöntemi.

Bu kadar.


1

UICollectionViewDelegateFlowLayout yöntemini uygularsanız:

- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath

Aradığınızda collectionview performBatchUpdates:completion:, boyut yüksekliği sizeForItemAtIndexPathyerine kullanılacaktır preferredLayoutAttributesFittingAttributes.

Oluşturma işlemi performBatchUpdates:completionyöntemden geçer, preferredLayoutAttributesFittingAttributesancak değişikliklerinizi yoksayar.


Bu yanlış davranışı gördüm, ancak sadece tahmini boyut sıfır olduğunda. Tahmini bir boyut belirlediğinizden emin misiniz?
dgatwood

1

Kime yardım edebilirse,

Ben estimatedItemSizeayarlanmış olsaydı o kötü bir kaza oldu. 0 returnedçeri iade etsem bile numberOfItemsInSection. Bu nedenle, hücrelerin kendileri ve otomatik düzenleri çökmenin nedeni değildi ... collectionView boşken bile çöktü, çünkü sadece estimatedItemSizekendi kendine boyutlandırma için ayarlanmıştı.

Benim durumumda bir collectionView içeren bir denetleyiciden collectionViewController için projemi yeniden düzenledim ve işe yaradı.

Git şekil.


1
collectionView.collectionViewLayout.invalidateLayout()Sonra aramayı deneyin collectionView.reloadData().
chengsam

ios10 ve altı için bu kodu ekleyin func viewWillLayoutSubviews () {super.viewWillLayoutSubviews (), #available (iOS 11.0, *) {} else {mainCollectionView.collectionViewLayout.invalidateLayout ()}} `
Marosdee Uma

1

Her şeyi şanssız deneyen herkes için, benim için çalışmasını sağlayan tek şey bu. Hücrenin içindeki çok satırlı etiketler için bu sihirli satırı eklemeyi deneyin:

label.preferredMaxLayoutWidth = 200

Daha fazla bilgi: burada

Şerefe!


0

Yukarıdaki örnek yöntem derlenmemiştir. İşte düzeltilmiş bir sürüm (ancak çalışıp çalışmadığına dair test edilmemiştir.)

override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 
{
    let attr: UICollectionViewLayoutAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes

    var newFrame = attr.frame
    self.frame = newFrame

    self.setNeedsLayout()
    self.layoutIfNeeded()

    let desiredHeight: CGFloat = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    newFrame.size.height = desiredHeight
    attr.frame = newFrame
    return attr
}

0

Daha fazla bilgi güncelleyin:

  • Kullanıyorsanız flowLayout.estimatedItemSizeiOS8.3'ün sonraki sürümünü kullanmanızı öneririz. İOS8.3'ten önce çökecektir [super layoutAttributesForElementsInRect:rect];. Hata mesajı:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

  • İkincisi, iOS8.x sürümünde flowLayout.estimatedItemSizefarklı bölüm iç metin ayarının çalışmamasına neden olur. yani fonksiyon: (UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:.


0

Çözüm 4 önemli adımdan oluşur:

  1. Dinamik hücre boyutlandırmayı etkinleştirme

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

  1. Otomatik yerleşimi etkinleştirmediği sürece, otomatik boyutlandırmayı contentViewve hücrenin kenarlarına sabitle özelliğini etkinleştir , çünkü contentViewotomatik boyutlandırmayı önler.
class MultiLineCell: UICollectionViewCell{

    private var textViewHeightContraint: NSLayoutConstraint!

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .cyan
        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentViewWidthAnchor = contentView.widthAnchor.constraint(equalToConstant: 0)

        NSLayoutConstraint.activate([
            contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    } 
    ...
}
  1. collectionView(:cellForItemAt:)ContentView genişliğini collectionView genişliğine sınırlamak için contentView.widthAnchor.constraint öğesini ayarlayın .

Aşağıdaki gibi olur; Biz hücrenin belirleriz maxWidthde CollectionView'ın genişliğine değişken collectionView(:cellForItemAt:)ve maxWidthbireyin didSetyönteme biz MaxWidth için widthAnchor.constant ayarlarsınız.

class ViewController: UIViewController, UICollectionViewDataSource {
    ...

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! MultiLineCell
        cell.textView.text = dummyTextMessages[indexPath.row]
        cell.maxWidth = collectionView.frame.width
        return cell
    }

    ...
}
class MultiLineCell: UICollectionViewCell{
    ....

    var maxWidth: CGFloat? {
        didSet {
            guard let maxWidth = maxWidth else {
                return
            }
            contentViewWidthAnchor.constant = maxWidth
            contentViewWidthAnchor.isActive = true
        }
    }

    ....
}

UITextView'ın kendi kendine boyutlandırmasını etkinleştirmek istediğiniz için ek bir adımı vardır;

4. UITextView öğesinin heightAnchor.constant değerini hesaplayın ve ayarlayın.

Yani, contentView genişliği ayarlanır zaman biz birlikte UITextView yüksekliğini ayarlamak gerekir didSetait maxWidth.

UICollectionViewCell içinde:

var maxWidth: CGFloat? {
    didSet {
        guard let maxWidth = maxWidth else {
            return
        }
        contentViewWidthAnchor.constant = maxWidth
        contentViewWidthAnchor.isActive = true

        let sizeToFitIn = CGSize(width: maxWidth, height: CGFloat(MAXFLOAT))
        let newSize = self.textView.sizeThatFits(sizeToFitIn)
        self.textViewHeightContraint.constant = newSize.height
    }
}

Bu adımlar size istenen sonucu verecektir. İşte tam çalıştırılabilir bir özü

Vadim Bulavin'e açık ve aydınlatıcı blog yazısı için teşekkürler - Koleksiyon Görünümü Hücreleri Kendinden Boyutlandırma: Adım Adım Eğitim


-2

Kullanmayı denedim estimatedItemSizeama estimatedItemSizehücre yüksekliğine eşit değilse hücreleri eklerken ve silerken bir sürü hata vardı . i ayarını durdurdu estimatedItemSizeve bir prototip hücre kullanarak dinamik hücre uyguladı. işte böyle yapılır:

bu protokolü oluştur:

protocol SizeableCollectionViewCell {
    func fittedSize(forConstrainedSize size: CGSize)->CGSize
}

bu protokolü özel olarak uygulayın UICollectionViewCell:

class YourCustomCollectionViewCell: UICollectionViewCell, SizeableCollectionViewCell {

    @IBOutlet private var mTitle: UILabel!
    @IBOutlet private var mDescription: UILabel!
    @IBOutlet private var mContentView: UIView!
    @IBOutlet private var mTitleTopConstraint: NSLayoutConstraint!
    @IBOutlet private var mDesciptionBottomConstraint: NSLayoutConstraint!

    func fittedSize(forConstrainedSize size: CGSize)->CGSize {

        let fittedSize: CGSize!

        //if height is greatest value, then it's dynamic, so it must be calculated
        if size.height == CGFLoat.greatestFiniteMagnitude {

            var height: CGFloat = 0

            /*now here's where you want to add all the heights up of your views.
              apple provides a method called sizeThatFits(size:), but it's not 
              implemented by default; except for some concrete subclasses such 
              as UILabel, UIButton, etc. search to see if the classes you use implement 
              it. here's how it would be used:
            */
            height += mTitle.sizeThatFits(size).height
            height += mDescription.sizeThatFits(size).height
            height += mCustomView.sizeThatFits(size).height    //you'll have to implement this in your custom view

            //anything that takes up height in the cell has to be included, including top/bottom margin constraints
            height += mTitleTopConstraint.constant
            height += mDescriptionBottomConstraint.constant

            fittedSize = CGSize(width: size.width, height: height)
        }
        //else width is greatest value, if not, you did something wrong
        else {
            //do the same thing that's done for height but with width, remember to include leading/trailing margins in calculations
        }

        return fittedSize
    }
}

şimdi kontrol cihazınızı UICollectionViewDelegateFlowLayoutşu alana uydurun ve içinde şu alana sahip olun:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout {
    private var mCustomCellPrototype = UINib(nibName: <name of the nib file for your custom collectionviewcell>, bundle: nil).instantiate(withOwner: nil, options: nil).first as! SizeableCollectionViewCell
}

verileri bağlamak ve daha sonra bu verilerin dinamik olmasını istediğiniz boyutu nasıl etkilediğini belirlemek için bir prototip hücre olarak kullanılacaktır

Son olarak, UICollectionViewDelegateFlowLayout's collectionView(:layout:sizeForItemAt:)uygulanmalıdır:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    private var mDataSource: [CustomModel]

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)->CGSize {

        //bind the prototype cell with the data that corresponds to this index path
        mCustomCellPrototype.bind(model: mDataSource[indexPath.row])    //this is the same method you would use to reconfigure the cells that you dequeue in collectionView(:cellForItemAt:). i'm calling it bind

        //define the dimension you want constrained
        let width = UIScreen.main.bounds.size.width - 20    //the width you want your cells to be
        let height = CGFloat.greatestFiniteMagnitude    //height has the greatest finite magnitude, so in this code, that means it will be dynamic
        let constrainedSize = CGSize(width: width, height: height)

        //determine the size the cell will be given this data and return it
        return mCustomCellPrototype.fittedSize(forConstrainedSize: constrainedSize)
    }
}

ve bu kadar. Hücrenin boyutunu collectionView(:layout:sizeForItemAt:)bu şekilde döndürmek, kullanmamı engeller estimatedItemSizeve hücreleri yerleştirip silerim mükemmel çalışır.

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.