如果要换行的文本中有长字符串,则 sizeWithFont 不会为 UITextView 提供正确的高度

Posted

技术标签:

【中文标题】如果要换行的文本中有长字符串,则 sizeWithFont 不会为 UITextView 提供正确的高度【英文标题】:sizeWithFont doesn't give correct height for UITextView if there is a long string in the text being wrapped 【发布时间】:2010-02-25 01:23:32 【问题描述】:

有没有办法获得正确大小的 NSString 使用:

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

不会被 2 或 300 个字符串抛弃。目前,如果我尝试在这些长字符串上使用此方法,则会错误地计算它们,最终在 UITextView 的底部会出现大量空白。

我尝试过使用 UILineBreakModeWordWrap 和 UILineBreakModeCharacterWrap。

正在调整大小

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
    CGFloat     result = 44.0f;
    NSString*   text = nil;
    CGFloat     width = 0;
    CGFloat     tableViewWidth;
    CGRect      bounds = [UIScreen mainScreen].bounds;

    tableViewWidth = bounds.size.width;


    width = tableViewWidth - 150;       

    text = stringWithLongWords;

    if (text) 
        CGSize      textSize =  width, 20000.0f ;     
        CGSize      size = [text sizeWithFont:[UIFont systemFontOfSize:10.0f] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];

        size.height += 50.0f;               
        result = MAX(size.height, 44.0f+30.0f); 
    

    return result;

【问题讨论】:

你到底想做什么?我认为 sizeWithFont: 效果很好,也许这就是您将这些信息应用于 UITextView 的方式。请解释一下。 我有一个自定义 UITableView 单元格,其中有 2 个 UILabel 和一个 UITextView,使用 sizeWithFont 来计算单元格高度所需的大小,有时单元格最终会超过 400 像素。 【参考方案1】:

UITextView 与包裹在UIScrollView 中的UILabel 不完全相同。它的行距不同于sizeWithFont:constrainedToSize:linkBreakMode: 不考虑的字体大小和边距。

了解您的字体大小后,您或许可以计算行数并考虑行距。你可以在空白处猜测并尝试欺骗sizeWithFont: 以给出更有用的答案。

流行的解决方案似乎是:

如果您不需要任何 UITextView 功能,只需使用 UILabel

如果您需要hyperlinks,请将看起来像超链接的UIButtons 覆盖在UILabel

使用屏幕外的UITextView 及其sizeToFit 方法来获得真正的答案

我对第 3 个选项没有运气,但听起来它应该可以工作,所以也许我做错了什么。

我将尝试使用UILabel 和覆盖超链接的按钮。我们会看看结果如何。

如果失败,Loren Brichter(Tweetie 成名)总是有一个选择:使用CoreGraphics 将所有内容绘制到UIView 中。

祝你好运!

【讨论】:

第三个选项可能不起作用,因为 sizeToFit 在 UITextView 呈现到屏幕之前不起作用。只是一个想法。 有趣。我想知道您是否可以在屏幕上渲染它,但使用 alpha = 0 或非常低的值来欺骗它进行渲染,但人眼仍然看不到。 这可能会奏效,而且会是一个有趣的实验。不过,我很想找到一种在渲染之前正确计算高度的方法。在 UITableViewCells 中使用 UITextViews 时会非常有用。 第三个选项只在 ios6 中对我有用。看起来与 ***.com/questions/18859637/… 相关的东西相当于 sizeWithFont: 在这里讨论:***.com/questions/18903304/… 这里的实际解决方案(以及问题的原因):***.com/a/27322396/2057171【参考方案2】:

查看这篇帖子How do I size a UITextView to its content?

看起来 textView.contentSize.height 应该可以工作(需要注意的是正确的 contentSize 只有在 UITextView 使用 addSubview 添加到视图后才可用)

【讨论】:

【参考方案3】:

你说你有一个不同高度的UITableView。您是否将所有单元格的重用标识符设置为相同的值?可能是已经设置了高度的旧单元正在被重复使用。如果这是问题所在,您应该在重新使用单元格时再次调整其大小。

【讨论】:

UITableView 上只有一个这种类型的单元格,我检查了这是否是一个问题,但似乎不是。【参考方案4】:

到目前为止,我发现的最佳解决方案是使用相同的字体设置单独隐藏 UITextView,并设置其文本。之后,它的 contetSize 应该是准确的。

【讨论】:

【参考方案5】:

您使用的宽度是 UITextView 的宽度...但您并不关心该宽度,您关心的是嵌套在文本视图中的实际文本区域的宽度。

默认情况下,UITextView 的边框周围有填充,以在键入的文本和 UITextView 的边缘之间产生几个像素宽(顶部长)的空间...要获得正确的大小,您应该不要使用

textView.frame.size.width

而是,

textView.frame.size.width-(textView.contentInset.left+textView.contentInset.right+textView.textContainerInset.left+textView.textContainerInset.right+textView.textContainer.lineFragmentPadding/*left*/+textView.textContainer.lineFragmentPadding/*right*/)

^它采用 UITextView 的宽度并减去所有填充,因此您只剩下可输入文本区域的宽度。

除了lineFragmentPadding 没有底部之外,高度也是如此,因此您只需将其减去一次而不是两次。


最后的代码是这样的:

    CGSize textViewContentSize = CGSizeMake(theTextView.frame.size.width-(theTextView.contentInset.left+theTextView.contentInset.right+theTextView.textContainerInset.left+theTextView.textContainerInset.right+theTextView.textContainer.lineFragmentPadding/*left*/+theTextView.textContainer.lineFragmentPadding/*right*/), theTextView.frame.size.height-(theTextView.contentInset.top+theTextView.contentInset.bottom+theTextView.textContainerInset.top+theTextView.textContainerInset.bottom+theTextView.textContainer.lineFragmentPadding/*top*//*+theTextView.textContainer.lineFragmentPadding*//*there is no bottom padding*/));

    CGSize calculatedSize = [theTextView.text sizeWithFont:theTextView.font
                                          constrainedToSize:textViewContentSize
                                              lineBreakMode:NSLineBreakByWordWrapping];


    CGSize adjustedSize = CGSizeMake(ceilf(calculatedSize.width), ceilf(calculatedSize.height));

【讨论】:

【参考方案6】:

受@MrNickBarker 的回答启发,这是我的解决方案:

CGFloat width = 280.0f;

UITextView *t = [[UITextView alloc] init];
[t setFont:[UIFont systemFontOfSize:17]];
[label setText:@"some short or long text, works both"];

CGRect frame = CGRectMake(0, 0, width, 0);
[t setFrame:frame];
// Here's the trick: after applying the 0-frame, the content size is calculated and can be used in a second invocation
frame = CGRectMake(0, 0, width, t.contentSize.height);
[t setFrame:frame];

留给我的唯一问题是这不适用于修改后的插图。

仍然无法相信需要这样的扭曲,但由于-[NSString sizeWithFont:forWidth:lineBreakMode:] 不尊重插入、填充、边距、行间距等,看来这是目前唯一可行的解​​决方案(即 iOS 6)。

【讨论】:

以上是关于如果要换行的文本中有长字符串,则 sizeWithFont 不会为 UITextView 提供正确的高度的主要内容,如果未能解决你的问题,请参考以下文章

隐藏网格列改变行的高度

excel怎么换行:Excel表格换行教程

DIV设置浮动float以后下一个DIV要换行的方法

c语言中 在编辑窗口,如果printf函数内字符过长,想要在编辑窗口换行,而且编译时不出问题,怎么办?

C# 中richitextBoX中显示的文本怎么换行

MATLAB fwrite 怎么换行