在 UITableViewCell 内展开 UITextView

Posted

技术标签:

【中文标题】在 UITableViewCell 内展开 UITextView【英文标题】:Expanding UITextView inside UITableViewCell 【发布时间】:2014-02-19 16:32:58 【问题描述】:

关于 SO 的问题有十几个类似的问题,但似乎没有就最佳方式达成共识。此外,我还没有找到任何适合我的解决方案。我的自定义 UITableViewCell 的不同之处在于我有两个标签,其中一个在它自己的视图中,还有一个文本视图。这三个都应该扩展到它们的内容。

我想知道是不是我的约束设置不正确,但我不确定我会调整什么。

这是我在 IB 的牢房。

内容视图是浅红色的,顶部的额外视图是白色的,里面有一个标签。

当文本更改时,我保存文本并更新tableView

-(void)textViewDidChange:(UITextView *)textView

    NSLog(@"row: %i", textView.tag);
    [self.textStrings setObject:textView.text atIndexedSubscript:textView.tag];
    [self.tableView beginUpdates];
    [self.tableView endUpdates];

对于tableView:heightForRowAtIndexPath: 方法,我使用缓存的高度值(选定行除外)。在这种情况下,我将创建一个新单元格,对其进行配置,并使用systemLayoutSizeFittingSize: 获取高度。这似乎是最常见的solution。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    // use cached height if there is one (and it isn't the selected row)
    if ([self.selectedRow integerValue] != indexPath.row && indexPath.row < [self.rowHeights count])
        return [[self.rowHeights objectAtIndex:indexPath.row] floatValue];
    

    static NSString *CellIdentifier = @"RMTextViewCell";
    RMTextViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    [self configureCell:cell forIndexPath:indexPath];

    [cell layoutIfNeeded];

    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    height += 1; // add 1 for border

    NSNumber *h = @(height);
    [self.rowHeights setObject:h atIndexedSubscript:indexPath.row];

    return height;

textView 确实展开了,但是当它进入多行时,顶部标签开始被剪裁。在某些版本中,当文本更改时,我已经让 textView 开始剪切/扩展。似乎自动布局不确定如何正确计算单元格的高度。

有什么想法吗?

这是我的Github project,里面有一些实验。重要文件是ViewControllers/RMTextViewTableViewControllerCell/RMTextViewCell。如果您运行它,请查看“带文本的动态单元格”。

【问题讨论】:

【参考方案1】:

似乎这可能是一个 ios 错误,因为我希望 UITextView 的高度将作为 UILabel 包含在它位于单元格的 contentView 中并且我们使用 systemLayoutSizeFittingSize 时。无论如何,正如 user501836 所说,您可以手动计算 textView 的高度。然后,您需要将其添加到为您的 contentView 计算的高度。这是我如何计算 tableView 中的单元格高度的示例:heightForRowAtIndexPath:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 


    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    CGSize textViewSize = [[cell textView] sizeThatFits:CGSizeMake([[cell textView] frame].size.width, FLT_MAX)];

    height += textViewSize.height;

    return height;


【讨论】:

【参考方案2】:

我也有同样的问题。 UITableViewCell 中的UILabel 计算正确,但UITableViewCell 中的UITextView 计算不正确。

所以只能手动计算高度:

CGSize textViewSize = [cell.textView sizeThatFits:CGSizeMake(cell.textView.frame.size.width, FLT_MAX)];

【讨论】:

如何添加单元格的其余部分,因为标签也可以是多行? 终于想通了。我将在未来的某个时候发布更多关于我如何进行计算的细节。谢谢。 你能发布这些细节 RyanJM 吗?我有同样的问题 同上,同样的问题,如果你能发布你的解决方案,那就太好了!【参考方案3】:

我一直在寻找一种适用于 iOS7 和 iOS8 的解决方案。基于上面jobb的回答,我添加了一些代码来使用UITextView.contextSize与UITextView.frame.size处理旋转。

我还发现在 xCode 6 中似乎 systemLayoutSizeFittingSize 正在考虑 UITextView 的 textContainerInsets。所以我发现在向 systemLayoutSizeFittingSize 添加额外高度之前将它们设置为零可以更好地设置间距。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    // Get the cell once and save it in an NSDictionary. Thisupports cases with multiple cells types.
    CCTextViewCell *sizingCell = [self.offscreenCells objectForKey:CellIdentifier];
    if (!sizingCell) 
        sizingCell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        [self.offscreenCells setObject:sizingCell forKey:CellIdentifier];
    

    [self populateCellViewWithData:sizingCell atIndexPath:indexPath];

    sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(sizingCell.bounds));
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    // UITextViews don't autosize well with systemLayoutSizeFittingSize.
    // We need to add the sum of the heights of the UITextViews without its textContainerInsets to the height.
    // We also need to set the textContainerInsets to zero so that systemLayoutSizeFittingSize give the right number.
    // So we do this first.
    CGFloat additionalUITextViewsHeight = 0;
    for (UIView *subVw in sizingCell.contentView.subviews) 
        if ([subVw isKindOfClass:[UITextView class]]) 
            UITextView *subTextView = (UITextView*) subVw;

            subTextView.textContainerInset = UIEdgeInsetsZero;
            CGSize textViewSize = [subTextView sizeThatFits:CGSizeMake(subTextView.contentSize.width, FLT_MAX)];
            additionalUITextViewsHeight += textViewSize.height;
        
    

    CGFloat height = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + additionalUITextViewsHeight;

    return height;

【讨论】:

以上是关于在 UITableViewCell 内展开 UITextView的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用为 UITableViewCell 的某些部分调用 DidSelect?

iOS 在点击时使用 AutoLayout 展开 UITableViewCell

在 Xamarin.iOS 中使用 UITableViewCell 展开 Segue

在 UITableViewCell 中选择后展开和折叠特定行

滚动后 UITableViewCell 标签发生变化[重复]

如何强制释放 UITableViewCell