简体   繁体   中英

Dynamic cell width of UICollectionView depending on label width

I have a UICollectionView, that loads cells from reusable cell, which contains label. An array provides content for that label. I can resize label width depending on content width easily with sizeToFit. But I cannot make cell to fit label.

Here's the code

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

In sizeForItemAtIndexPath return the size of the text

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

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

Checkout below code you might be giving very short CGSize.

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

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

Swift 4.2+

Principle is:

  1. Implement UICollectionViewDelegateFlowLayout (it contains necessary method signature)

  2. Call collectionView...sizeForItemAt method.

  3. No need to bridge-cast String to NSString to call size(withAttributes: method. Swift String has it out of the box.

  4. Attributes are the same you set for (NS)AttributedString , ie font family, size, weight, etc. Optional parameter.


Sample solution:

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

But you would most likely want to specify concrete string attributes respective to your cell, hence final return would look like:

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

I have found a small trick for swift 4.2

For dynamic width & fixed height:

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

For dynamic height & fixed width:

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

在Swift 3中

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

斯威夫特4

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

In Swift 5.X, this single line of code is enough.

In the below answer i have added dynamic width and static height. Based on your requirement change height value.

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

Add UICollectionViewDelegateFlowLayout to your delegate

It's perfectly worked to me with equal cell space with dynamic cell size based on text length .

PFA image below...

在此处输入图片说明

//Create UICollectionView lazy var collectionView: UICollectionView = {

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

//add in view didload

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

UICollectionViewFlowLayout()这一行对我UICollectionViewFlowLayout()

collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM