Динамічна ширина комірки UICollectionView залежно від ширини мітки


94

У мене є UICollectionView, який завантажує комірки з багаторазової комірки, яка містить мітку. Масив забезпечує вміст для цієї мітки. Я можу легко змінити розмір ширини мітки залежно від ширини вмісту за допомогою sizeToFit. Але я не можу зробити клітинку відповідно до мітки.

Ось код

- (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;
}

подібна проблема ... stackoverflow.com/questions/24915443/… ???
Fattie

Відповіді:


85

У sizeForItemAtIndexPathповернути розмір тексту

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

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

4
Ви не уявляєте, як я вам дякую! Це справді працює. Тепер мені потрібно лише вирішити проблему [cell.myLabel sizeToFit], оскільки вона з’являється у повному розмірі лише після прокрутки. Але я навіть не був близький до вашого рішення.
целюлоза

дякую за допомогу, але я все ще маю одне питання. Коли я коментую [cell.myLabel sizeToFit], у мене є усічені слова, а букви вирізані внизу, але це стає нормально після прокрутки (слова мають нормальний розмір, а букви трохи підскакують). Якщо я коментую та вимикаю повідомлення [cell.myLabel sizeToFit] (я вирішив пограти з IB, і це чудово працює), у мене є слова, вирізані в кінці та внизу. Я зробив скріншот goo.gl/HaoqQV Це не дуже чітко на дисплеях, що не мають сітківки, але ви бачите, що літери вирізали. Ваша пропозиція щодо вирішення буде дуже вдячна!
целюлоза

2
замість sizeToFit, використовуйте sizeWithAttributes, щоб отримати розмір CGS тексту, а потім встановіть рамку мітки з новим розміром.
Basheer_CAD

дякую за пропозицію, але у мене все ще є вирізаний myLabel внизу та в кінці. Можливо, я помиляюся з реалізацією вашої пропозиції. Ось мій код
целюлоза

- (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; }
целюлоза

49

Свіфт 4.2+

Принцип:

  1. Переконайтесь, що делегування налаштоване (наприклад collectionView.delegate = self)

  2. Реалізація UICollectionViewDelegateFlowLayout(вона містить необхідний підпис методу).

  3. collectionView...sizeForItemAtМетод дзвінка .

  4. Немає необхідності бридж-кидок Stringдо NSStringдля виклику size(withAttributes:методу. СтрімкийString це з коробки.

  5. Атрибути однакові для вас (NS)AttributedString, тобто сімейство шрифтів, розмір, вага тощо. Необов’язковий параметр.


Зразок рішення:

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

Але ви, швидше за все, хочете вказати конкретні атрибути рядка, що відповідають вашій комірці, отже, остаточне повернення буде виглядати так:

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
    }
}

Чому НЕ ПОВИНЕН використовувати UILabel для обчислення розміру? Ось запропоноване рішення:

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

Так, ви отримуєте той самий результат. Це виглядає спрощеним і може здатися оптимальним рішенням. Але це неправильно, оскільки: 1) це дорого, 2) накладні витрати і 3) брудне.

Це дорого, тому що UILabel - це складний об'єкт інтерфейсу, який створюється на кожній ітерації кожного разу, коли ваша комірка збирається показатись, хоча вам тут і не потрібно. Це накладне рішення, оскільки вам потрібно лише отримати розмір тексту, але ви заходите так далеко, щоб створити цілий об’єкт інтерфейсу. І з цієї причини брудно.


1
не забудьте встановитиcollectionView.delegate == self // or whatever-object-which-do-it
Фіцю

Чудова відповідь. Хоча розмір, який я отримував, був трохи меншим, ніж мав бути, на різній довжині рядків я вирішив трохи змінити розмір. Додавши додаткові 5 очок до ширини, це зробило трюк:CGSize(width: title.size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]).width + 5, height: 50)
Старскі

37

Я знайшов невеликий фокус для швидкої 4.2

Для динамічної ширини та фіксованої висоти:

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)
    }

Для динамічної висоти та фіксованої ширини:

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
Будьте обережні, використовуючи це. Створення та креслення нового UILabel для кожного розрахунку комірки дуже дороге.
AnthonyR

потрібно додати UICollectionViewDelegateFlowLayout
cristianego

3
Щоб звернутися до коментаря про те, що це дороге створення фіктивного ярлика, можливо, ви можете просто створити один фіктивний ярлик замість кількох. Все, що ви дійсно хочете від нього, - це розмір тексту з атрибутів міток. Врешті-решт, це, по суті, те саме, що обчислюється розмір тексту за допомогою sizeWithAttributes, тому, можливо, це найкраща відповідь.
Стівен Пол

@Hassan Дякую, брате, це спрацювало для мене, але я знайшов проблему в ширині, тому додав return CGSize (ширина: label.frame.width + 50, висота: 32). Тоді це спрацювало, я думаю, що ця відповідь повинна бути у верхньому списку.
Аршад Шаїк

27

Оформлення нижче коду ви можете дати дуже короткий CGSize.

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

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

@Vineesh TP Дякую за вашу відповідь, я обов’язково перевірю це і повідомлю вас!
целюлоза

+1000 Цей, безумовно, працює. Ваш і пост Башира повинні мати зелений галочку разом.
скелястий єнот

Будь-яка ідея, як це зробити за допомогою swift 3?
UKDataGeek

1
Дякую Людині, час його вечірок !!
Раві


14

Стрімкий 4

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

0

// додаємо до перегляду didload

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.