所有方向的UITableViewCell中的动态UILabel高度/宽度

Bob*_*ryn 15 uikit ios

我的问题基本上归结为在UITableCell中支持UILabel的动态高度(我想其他元素)的最佳方法,并且在旋转时正确地调整标签宽度/高度和单元格高度.

我知道如何获得UILabels的预期高度,并相应地调整高度,但是当你支持横向时,事情似乎也变得非常棘手.

我认为这可能是layoutSubviews的路线,但我不确定如何将它与需要计算单元格高度的表结合起来.另一篇有趣的帖子在init上手动设置框架,以确保它们在已知数量的情况下进行计算,但这只能解决部分问题.

所以这是我正在处理的图像,红色箭头指向动态高度标签,蓝色箭头指向将改变高度的单元格.

动态UILabel /单元格高度/宽度

我已经设法让它正常工作,但不确定它是否是正确的方法.

以下是我学到的一些内容:

  • cell.frame in cellForRowAtIndexPath始终以纵向模式显示其大小.(即,对于iPhone应用程序,它总是报告320).
  • 在属性中存储原型单元格以供参考具有相同的问题,始终处于纵向模式
  • 在这个用例中,标签宽度的自动调整掩码似乎没用,事实上导致计算旋转高度的问题
  • tableView.frame以cellForRowAtIndexPath正确的方向给出其大小
  • 你需要[tableView reloadData]轮换.我找不到任何其他方法来更新单元格和标签高度

以下是我为此工作所采取的步骤:

  1. 禁用UILabel上的任何自动调整大小的掩码,因为它们会因某种原因干扰获取正确的标签高度
  2. viewDidLoad我获取对每个标签字体的引用,以及与纵向中的tableView相比标签宽度百分比的浮点数

    CWProductDetailDescriptionCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"DescriptionCell"];
    self.descriptionLabelWidthPercentage = cell.descriptionLabel.frame.size.width / 320;
    self.descriptionLabelFont = cell.descriptionLabel.font;
    
    Run Code Online (Sandbox Code Playgroud)
  3. heightForRowAtIndexPath我使用tableView宽度和我已经抓住的百分比计算单元格高度:

    case TableSectionDescription:
        CGFloat labelWidth = self.tableView.frame.size.width * self.descriptionLabelWidthPercentage;
        CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(labelWidth, MAXFLOAT) AndFont:self.descriptionLabelFont];
        return newLabelFrameSize.height + kTextCellPadding;
    
    Run Code Online (Sandbox Code Playgroud)
  4. cellForRowAtIndexPath我计算标签框架的框架并更新它

    cell = [tableView dequeueReusableCellWithIdentifier:@"DescriptionCell"];
    ((CWProductDetailDescriptionCell *)cell).descriptionLabel.text = self.product.descriptionText;
    CGRect oldFrame = ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame;
    CGFloat labelWidth = self.tableView.frame.size.width * self.descriptionLabelWidthPercentage;
    CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(labelWidth, MAXFLOAT) AndFont:((CWProductDetailDescriptionCell *)cell).descriptionLabel.font];
    ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, labelWidth, newLabelFrameSize.height);
    
    Run Code Online (Sandbox Code Playgroud)
  5. didRotateFromInterfaceOrientation你需要[self.tableView reloadData]

这种方法有问题:

  1. 您无法利用可能在IB中设置的自动调整遮罩和边距
    • 那些似乎在你退回细胞之后才会开火cellForRowAtIndexPath (不确定这是否正确)
    • 他们以某种方式弄乱了高度计算,你的标签最终比景观.
  2. 如果您的标签宽度在纵向横向上的百分比不相等,则您需要知道这两个百分比
  3. 您需要知道/计算标签宽度百分比.理想情况下,您可以在自动调整大小的蒙版完成后立即计算这些内容.
  4. 它只是感觉笨拙.我有一种感觉,我会在编辑模式中遇到更多令人头疼的问题.

所以.这样做的正确方法是什么?我已经看过很多SO问题,但没有一个完全解决这个问题.

Bob*_*ryn 12

显然,它写出了我的巨大问题,并从计算机中休息了解.

所以这是解决方案:

动态计算UILabel高度的主要步骤,并利用自动调整掩码:

  1. 为每个需要调整高度的单元格保留原型单元格
  2. heightForRowAtIndexPath
    • 根据您所在的方向调整参考单元格宽度
    • 然后,您可以可靠地使用包含的UILabel框架宽度来计算高度
  3. cellForRowAtIndexPath除初始设置外, 不要进行任何帧调整
    • UITableViewCells在调用之后立即执行所有布局工作,所以你的努力充其量是徒劳的,最糟糕的是他们搞砸了
  4. 进行框架调整 willDisplayCell forRowAtIndexPath
    • 我很生气,我忘了这件事
    • 它出现在所有UITableViewCell内部布局之后,就在它绘制之前
    • 带有自动调整遮罩的标签已经具有可用于计算的正确宽度

在viewDidLoad中抓取对需要高度调整的单元格的引用

请注意,这些是保留/强(ARC),并且从不添加到表本身

self.descriptionReferenceCell = [self.tableView dequeueReusableCellWithIdentifier:@"DescriptionCell"];
self.attributeReferenceCell = [self.tableView dequeueReusableCellWithIdentifier:@"AttributeCell"];
Run Code Online (Sandbox Code Playgroud)

heightForRowAtIndexPath计算可变高度单元格

我首先更新我的参考单元格的宽度,以便它显示其子视图(UILabels),然后我可以将其用于计算.然后我使用更新的标签宽度来确定标签的高度,并添加任何必要的单元格填充来计算我的单元格高度.(请记住,只有当您的细胞与标签一起改变高度时,才需要进行这些计算).

UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
float width = UIDeviceOrientationIsPortrait(orientation) ? 320 : 480;

case TableSectionDescription:
    CGRect oldFrame = self.descriptionReferenceCell.frame;
    self.descriptionReferenceCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, width, oldFrame.size.height);
    CGFloat referenceWidth = self.descriptionReferenceCell.descriptionLabel.frame.size.width;
    CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(referenceWidth, MAXFLOAT) AndFont:self.descriptionReferenceCell.descriptionLabel.font];
    return newLabelFrameSize.height + kTextCellPadding;
Run Code Online (Sandbox Code Playgroud)

cellForRowAtIndexPath不要依赖方向做任何动态布局相关更新

willDisplayCell forRowAtIndexPath更新标签高度本身

由于表格单元格已经执行layoutSubviews,标签已经具有正确的宽度,我用它来计算标签的确切高度.我可以安全地更新我的标签高度.

case TableSectionDescription:
    CGRect oldFrame = ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame;
    CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(oldFrame.size.width, MAXFLOAT) AndFont:((CWProductDetailDescriptionCell *)cell).descriptionLabel.font];
    ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, newLabelFrameSize.height);
    break;
Run Code Online (Sandbox Code Playgroud)

旋转时重新加载数据

如果不重新加载数据,则可见单元格不会更新其高度和标签.

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    [self.tableView reloadData];
}
Run Code Online (Sandbox Code Playgroud)

唯一需要指出的是,我正在使用帮助程序类来计算仅包装基本调用的标签高度.真的,它不再保存任何代码(我曾经有其他东西),所以只需直接使用正常的方法你的字符串.

- (CGSize) sizeForString:(NSString*)string WithConstraint:(CGSize)constraint AndFont:(UIFont *)font {
    CGSize labelSize = [string sizeWithFont:font
                          constrainedToSize:constraint 
                              lineBreakMode:UILineBreakModeWordWrap];
    return labelSize;
}
Run Code Online (Sandbox Code Playgroud)