Динамическая ширина ячейки UICollectionView в зависимости от ширины метки

У меня есть 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;
}

11 ответов

Решение

В sizeForItemAtIndexPath вернуть размер текста

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

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

Swift 4.2+

Принцип таков:

  1. Воплощать в жизнь UICollectionViewDelegateFlowLayout (содержит необходимую подпись метода)

  2. Вызов collectionView...sizeForItemAt метод.

  3. Не нужно накидывать мост String в NSString звонить size(withAttributes: метод. стриж String есть это из коробки.

  4. Атрибуты те же, что вы установили для (NS)AttributedStringт. е. семейство шрифтов, размер, вес и т. д. Необязательный параметр.


Пример решения:

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

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

// Replace "String" with proper string (typically array element). 
return "String".size(withAttributes: [
    NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14)
])

Я нашел маленький трюк для быстрой 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)
        }

Оформить заказ ниже код, который вы могли бы дать очень короткий CGSize.

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

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

В Swift 5.X этой единственной строчки кода достаточно.

В ответе ниже я добавил динамическую ширину и статическую высоту. В зависимости от ваших требований измените значение высоты.

      //MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: itemsArray[indexPath.item].size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 17)]).width + 25, height: 30)
}

Добавьте UICollectionViewDelegateFlowLayout к своему делегату

В Свифт 3

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

Swift 4

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

осуществлять

      UICollectionViewDelegateFlowLayout

и добавьте код

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

    let label = UILabel(frame: CGRect.zero)
    label.text = arr[indexPath.row]
    label.sizeToFit()
    return CGSize(width: (label.frame.width+20), height: label.frame.size.height+20)

}

//Создаем UICollectionView

      lazy var collectionView: UICollectionView = {
    
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    
    
    //CollectionCellView width autoSize
    layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
   
    collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
   [enter image description here][1]
    return collectionView
}()

// добавить в вид didload

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    [layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    layout.estimatedItemSize = CGSizeMake(self.breadScrumbCollectionView.frame.size.width, 30); 
self.breadScrumbCollectionView.collectionViewLayout = layout;

Эта одна строка для моего UICollectionViewFlowLayout() сделал трюк для меня:

      collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
Другие вопросы по тегам