ios UICollectionView 的动态单元格宽度取决于标签宽度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23134986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:58:18  来源:igfitidea点击:

Dynamic cell width of UICollectionView depending on label width

iosobjective-cswiftuicollectionviewuicollectionviewcell

提问by pulp

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.

我有一个 UICollectionView,它从包含标签的可重用单元格加载单元格。数组为该标签提供内容。我可以使用 sizeToFit 根据内容宽度轻松调整标签宽度。但我无法制作适合标签的单元格。

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

采纳答案by Basheer_CAD

In sizeForItemAtIndexPathreturn the size of the text

作为sizeForItemAtIndexPath回报文本的大小

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

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

回答by Hexfire

Swift 4.2+

斯威夫特 4.2+

Principle is:

原则是:

  1. Make sure delegation is set up (e.g. collectionView.delegate = self)

  2. Implement UICollectionViewDelegateFlowLayout(it contains necessary method signature).

  3. Call collectionView...sizeForItemAtmethod.

  4. No need to bridge-cast Stringto NSStringto call size(withAttributes:method. Swift Stringhas it out of the box.

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

  1. 确保设置了委托(例如collectionView.delegate = self

  2. 实现UICollectionViewDelegateFlowLayout(它包含必要的方法签名)。

  3. 调用collectionView...sizeForItemAt方法。

  4. 无需桥接投StringNSString调用size(withAttributes:方法。斯威夫特String开箱即用。

  5. 属性与您为 设置的相同(NS)AttributedString,即字体系列、大小、粗细等。可选参数。



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:

但是您很可能希望为您的单元格指定具体的字符串属性,因此最终返回如下所示:

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

Why you SHOULD NOT use UILabel to calculate the size?Here's the suggested solution:

为什么不应该使用 UILabel 来计算大小?这是建议的解决方案:

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

Yes, you get same result. It looks simplistic and may seem as a go-to solution. But it's improper because: 1) it's expensive, 2) overhead and 3) dirty.

是的,你得到相同的结果。它看起来很简单,似乎是一种首选解决方案。但这是不正确的,因为:1)它很昂贵,2)开销和 3)脏。

It's expensive because UILabel is a complex UI object, which is being created on every iteration whenever your cell is about to show even though you don't need it here. It's an overhead solution because you only need to get sizeof a text, but you go as far as to create a whole UI object. And it's dirty for that reason.

它很昂贵,因为 UILabel 是一个复杂的 UI 对象,每当您的单元格即将显示时,它都会在每次迭代时创建,即使您在这里不需要它。这是一个开销解决方案,因为您只需要获取文本的大小,但您甚至可以创建整个 UI 对象。因此它很脏。

回答by Hassan Izhar

I have found a small trick for swift 4.2

我发现了 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)
        }

回答by Raza.najam

Checkout below code you might be giving very short CGSize.

签出下面的代码,您可能会给出非常短的 CGSize。

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

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

回答by Johnson

In Swift 3

在斯威夫特 3

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

回答by Barath

Swift 4

斯威夫特 4

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

回答by Apurva Gaikwad

//add in view didload

//在视图中添加didload

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