Etiket genişliğine bağlı olarak UICollectionView dinamik hücre genişliği


94

Hücreleri etiket içeren yeniden kullanılabilir hücreden yükleyen bir UICollectionView var. Bir dizi bu etiket için içerik sağlar. SizeToFit ile içerik genişliğine bağlı olarak etiket genişliğini kolayca yeniden boyutlandırabilirim. Ama hücreyi etikete sığdıramıyorum.

İşte kod

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    arrayOfStats =  @[@"time:",@"2",@"items:",@"10",@"difficulty:",@"hard",@"category:",@"main"];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:     (NSInteger)section{
    return [arrayOfStats count];
}

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

    return CGSizeMake(??????????);
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

    return 1;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    Cell *cell = (Cell *) [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath];
    cell.myLabel.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]];
    // make label width depend on text width
    [cell.myLabel sizeToFit];

    //get the width and height of the label (CGSize contains two parameters: width and height)
    CGSize labelSize = cell.myLbale.frame.size;

    NSLog(@"\n width  = %f height = %f", labelSize.width,labelSize.height);

    return cell;
}

benzer türde bir sorun ... stackoverflow.com/questions/24915443/… ???
Şişko

Yanıtlar:


85

Karşılığında sizeForItemAtIndexPathmetnin boyutu

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

    return [(NSString*)[arrayOfStats objectAtIndex:indexPath.row] sizeWithAttributes:NULL];
}

4
Sana nasıl teşekkür ettiğimi hayal bile edemezsin! Bu gerçekten işe yarıyor. Şimdi yalnızca [cell.myLabel sizeToFit] sorununu çözmem gerekiyor, çünkü bu sorun yalnızca kaydırmadan sonra tam boyutunda görünüyor. Ama çözümünüze yaklaşmadım bile.
pulp

Yardımın için teşekkürler ama hala bir sorunum var. [Cell.myLabel sizeToFit] açıklamasını kaldırdığımda, sözcüklerim kesilmiş ve harfler altta kesilmiş ama kaydırdıktan sonra tamam oluyor (sözcükler normal boyuttadır ve harfler biraz yukarı zıplar). [Cell.myLabel sizeToFit] mesajını yorumlayıp devre dışı bırakırsam (IB ile oynamaya karar verdim ve iyi çalışıyor), sonunda ve altta kesilmiş kelimelerim var. Bir ekran görüntüsü aldım goo.gl/HaoqQV Retina olmayan ekranlarda çok keskin değil ancak harflerin kesildiğini görebilirsiniz. Nasıl çözüleceğine dair öneriniz gerçekten takdir edilecek!
pulp

2
sizeToFit yerine, metnin CGSize değerini almak için sizeWithAttributes kullanın, ardından etiketin çerçevesini yeni boyutla ayarlayın.
Basheer_CAD

Öneriniz için teşekkür ederim ama yine de altta ve sonunda myLabel kesti. Belki de önerinizin uygulanmasında yanılıyorum. İşte kodum
pulp

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ Cell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"qw" forIndexPath:indexPath]; cell.myLbale.text = [NSString stringWithFormat:@"%@",[arrayOfStats objectAtIndex:indexPath.item]]; CGSize textSize; textSize = [[arrayOfStats objectAtIndex:indexPath.item] sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0f]}]; [cell.myLbale sizeThatFits:textSize]; //[cell.myLbale sizeToFit]; return cell; }
pulp

50

Swift 4.2+

İlke şudur:

  1. Yetkilendirmenin ayarlandığından emin olun (örneğin collectionView.delegate = self)

  2. Uygulama UICollectionViewDelegateFlowLayout(gerekli yöntem imzasını içerir).

  3. Çağrı collectionView...sizeForItemAtyöntemi.

  4. Köprü döküm gerek yok Stringetmek NSStringçağrısına size(withAttributes:yöntemle. Swift Stringkutudan çıkardı.

  5. Öznitelikler, sizin için ayarladığınızla aynıdır (NS)AttributedString, yani yazı tipi ailesi, boyutu, ağırlığı vb. İsteğe bağlı parametre.


Örnek çözüm:

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return "String".size(withAttributes: nil)
    }
}

Ancak büyük olasılıkla hücrenize ilişkin somut dize özniteliklerini belirtmek istersiniz, bu nedenle son dönüş şöyle görünür:

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        // dataArary is the managing array for your UICollectionView.
        let item = dataArray[indexPath.row]
        let itemSize = item.size(withAttributes: [
            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14)
        ])
        return itemSize
    }
}

Boyutu hesaplamak için neden UILabel KULLANMAMALISINIZ? İşte önerilen çözüm:

let label = UILabel(frame: CGRect.zero)
label.text = textArray[indexPath.item]
label.sizeToFit()

Evet, aynı sonucu alırsınız. Basit görünüyor ve bir çözüm olarak görünebilir. Ancak uygun değil çünkü: 1) pahalı, 2) genel giderler ve 3) kirli.

Pahalıdır çünkü UILabel, burada ihtiyacınız olmasa bile hücreniz gösterilmek üzere olduğunda her yinelemede oluşturulan karmaşık bir UI nesnesidir. Bu genel bir çözümdür çünkü yalnızca bir metnin boyutunu almanız gerekir , ancak tüm bir UI nesnesi oluşturacak kadar ileri gidersiniz. Ve bu nedenle kirli.


1
ayarlamayı unutmacollectionView.delegate == self // or whatever-object-which-do-it
Fitsyu

Mükemmel cevap. Aldığım boyut olması gerekenden biraz daha küçük olmasına rağmen, farklı uzunluktaki dizelerde, boyutu kendim değiştirmeye karar verdim. Genişliğe ek 5 nokta eklemek hile yaptı:CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Starsky

37

Hızlı 4.2 için küçük bir numara buldum

Dinamik genişlik ve sabit yükseklik için:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let label = UILabel(frame: CGRect.zero)
        label.text = textArray[indexPath.item]
        label.sizeToFit()
        return CGSize(width: label.frame.width, height: 32)
    }

Dinamik yükseklik ve sabit genişlik için:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            let label = UILabel(frame: CGRect.zero)
            label.text = textArray[indexPath.item]
            label.sizeToFit()
            return CGSize(width: 120, height: label.frame.height)
        }

8
Bunu kullanırken dikkatli olun. Her hücre hesaplaması için yeni bir UILabel oluşturmak ve çizmek çok pahalıdır.
AnthonyR

UICollectionViewDelegateFlowLayout eklemek gerekir
cristianego

3
Sahte bir etiket oluşturmanın pahalı olduğu hakkındaki yorumu ele almak için, belki birkaç etiket yerine tek bir sahte etiket oluşturabilirsiniz. Ondan gerçekten istediğiniz tek şey, etiket özelliklerinden gelen metin boyutu. Ancak günün sonunda, metin boyutunu hesaplamakla esasen aynıdır sizeWithAttributes, bu yüzden belki de tercih edilen cevap budur.
Stephen Paul

@Hassan Teşekkürler kardeşim benim için çalıştı, ama genişlikte bir sorun buldum, bu yüzden CGSize dönüşü eklendi (genişlik: etiket.frame.width + 50, yükseklik: 32). Sonra işe yaradı, bu cevabın en üst listede olması gerektiğini düşünüyorum.
Arshad Shaik

27

Aşağıdaki kodu kontrol edin, çok kısa CGSize veriyor olabilirsiniz.

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

    NSString *testString = @"SOME TEXT";
    return [testString sizeWithAttributes:NULL];
}

@Vineesh TP Cevabınız için teşekkür ederim, kesinlikle kontrol edip size haber vereceğim!
pulp

+1000 Bu kesinlikle işe yarıyor. Sizin ve Basheer'in gönderisinde birlikte yeşil bir onay işareti olmalıdır.
rocky rakun

Bunu Swift 3 ile nasıl yapacağınıza dair bir fikriniz var mı?
UKDataGeek

1
Teşekkürler Adam, Parti Zamanı !!
Ravi

18

Swift 3'te

let size = (arrayOfStats[indexPath.row] as NSString).size(attributes: nil)

14

Swift 4

let size = (arrayOfStats[indexPath.row] as NSString).size(withAttributes: nil)

0

// didload görünümüne ekle

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;
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.