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

我有一个 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;
}
115581 次浏览

sizeForItemAtIndexPath中返回文本的大小

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


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

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

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


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

在 Swift 3里

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

//添加视图确实负载

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

Swift 4

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

Swift 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 对象,每次迭代时,只要您的单元即将显示,就会创建它,即使您在这里并不需要它。 这是一个开销很大的解决方案,因为您只需要获得一个文本的 尺寸,但是您需要创建一个完整的 UI 对象。因为这个原因,它很脏。

我找到了一个快速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)
}

我的 UICollectionViewFlowLayout()的一句台词帮了我大忙:

collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

在 Swift 5.X 中,这一行代码就足够了。

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

视图代表流布局添加到委托

基于文本长度的动态单元格大小相等的单元格空间对我来说完美无缺。

PFA 图片如下..。

enter image description here

根据内容修复 CollectionView (而非单元格)的高度(集合视图的动态高度)

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

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