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

问题描述 投票:0回答:11

我有一个 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;
}
ios objective-c swift uicollectionview uicollectionviewcell
11个回答
90
投票

sizeForItemAtIndexPath
中返回文本的大小

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

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

79
投票

斯威夫特4.2+

原理是:

  1. 确保已设置委派(例如

    collectionView.delegate = self

  2. 实现

    UICollectionViewDelegateFlowLayout
    (包含必要的方法签名)。

  3. 调用

    collectionView...sizeForItemAt
    方法。

  4. 无需桥接

    String
    NSString
    来调用
    size(withAttributes:
    方法。 Swift
    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 是一个复杂的 UI 对象,每当你的单元格即将显示时,它都会在每次迭代中创建,即使你在这里不需要它。 这是一个开销解决方案,因为您只需要获取文本的size,但您甚至可以创建整个 UI 对象。因此它很脏。


45
投票

我发现了一个针对 swift 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)
        }

27
投票

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

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

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

22
投票

在 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 添加到您的委托中

它非常适合我,具有基于文本长度的动态单元格大小的相等单元格空间

下面的 PFA 图片...

根据内容修复collectionView(不是cell)的高度(集合视图的动态高度)

如何将UICollectionView的高度调整为UICollectionView内容大小的高度?


20
投票

在 Swift 3 中

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

15
投票

斯威夫特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;

0
投票

//创建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
}()

0
投票

实施

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)

}

-1
投票

我的

UICollectionViewFlowLayout()
的这一行对我来说很有效:

collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
© www.soinside.com 2019 - 2024. All rights reserved.