UITextView 文字在高度达到 8192.0 后变得不可见

Posted

技术标签:

【中文标题】UITextView 文字在高度达到 8192.0 后变得不可见【英文标题】:UITextView text becomes invisible after height reaches 8192.0 【发布时间】:2014-05-10 14:52:12 【问题描述】:

我在UIScrollView 中嵌入了一个不可滚动的UITextView,并动态地将文本添加到UITextViewUIScrollView 根据 TextView 的框架相应地调整它的 contentSize。但是,一旦UITextView 超过 8192 的高度,文本将变得不可见(但仍然存在,因为您可以使用放大镜突出显示文本,甚至可以通过放大镜看到部分文本)。

  CGRect textviewFrame = self.TextView.frame;
  textviewFrame.size.height = [self textViewHeightForAttributedText:self.TextView.attributedText andWidth:320.0];
  self.TextView.frame = textviewFrame;
  self.ScrollView.contentSize = self.TextView.frame.size;

帮助函数相应地调整UITextView的大小:

- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width

  UITextView *textView = [[UITextView alloc] init];
  [textView setAttributedText:text];
  CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
  return size.height;

直到我通过将最大尺寸强制为 8193 来明确测试它并出现问题(而最大尺寸为 8192 的文本仍然正确显示)之前,我才意识到它与 here 未解决的完全相同的问题.任何人以前遇到过这个问题并知道解决方法吗?谢谢

【问题讨论】:

问题不在于文字消失了。问题是文本视图的高度。这听起来像是一个主要的实现错误。解决方法很大程度上取决于您的 UI 细节。 看起来像一个错误,控件不应该这样。请向 Apple 提交错误报告。 @dasdom 我的 UI 的哪些细节对您有帮助?本质上,每当用户滚动到 UIScrollView 的底部时,都会向 UITextView 添加更多文本,并且更新 UIScrollView 的 contentSize。这发生在 scrollViewDidChange 方法中 有什么理由不使用文本视图的内部滚动行为?听起来您正在重新实现已经存在的实现。在内部,有一个内部视图,当您滚动时,它使用 TextKit 在需要的地方绘制文本。你的方法只是浪费内存和渲染时间。 【参考方案1】:

我最近遇到了这个问题,并找到了解决它的有效方法。虽然它看起来像一个 ios 错误恕我直言,但它真的不是...... CALayer 大小有实际限制,加上绘制 8K 高的文本需要很长时间。最好按照 Apple 的意图去做,并且只渲染可见的文本......这就是 UITextView 扩展 UIScrollView 的原因。

问题在于 UITextView 与 UI 的其他部分集成起来并不容易。就我而言,我正在开发一个新闻应用程序,其中使用单个 UITextView 来呈现文章,并且在其上方和下方有一些单独的 UI(标题和按钮等),所有这些都托管在单个可滚动容器中。

我找到的解决方案是将 UITextView 拆分为两个视图...一个专用的 UITextView 容器,其框架是全文大小(即与 UITextView 的 contentSize 大小相同),它是 UITextView 的超级视图。您的子 UITextView 的框架应设置为外部可滚动容器的边界。

然后您所要做的就是使用键值观察来监视外部可滚动容器视图的 contentOffset 属性(在我的情况下,这是一个 UICollectionView)。当它的 contentOffset 更改时,您会更新 (1) UITextView 的 contentOffset,以及 (2) UITextView 图层的 transform 属性。通过更新该转换属性, UITextView 被固定以填充其超级视图的当前可见部分。但是因为您还更新了 UITextView 的 contentOffset,所以这个诡计对用户来说是完全不可见的......它的外观和行为就像 UITextView 非常大一样。

【讨论】:

我花了很长时间才明白你在说什么......但它完全解决了我遇到的问题。谢谢! 很高兴它对其他人有用!这是一个非常有趣的黑客攻击【参考方案2】:

这是一个功能齐全的解决方案,适合任何想要的人!

** 假设您的内容大小不会超过 两个 文本视图的限制 **

此解决方案通过向视图添加两个 UITextView 并在它们之间拆分文本来工作。看起来很复杂,其实很简单!我刚刚写了一个非常详细的描述:)

第 1 步 - 将两个 UITextView 添加到您的视图中:

我在我的故事板中添加了我的。放置它们,使一个直接在另一个上方,它们之间没有空间。不用担心设置高度(我们稍后会设置)。

在视图上设置约束,以便它们从顶部和底部相互连接,并从所有其他侧面连接容器的周围边缘,包括您想要的填充。 将第一个文本视图从顶部、左侧和右侧绑定到容器,然后从底部绑定到第二个文本视图。将第二个文本视图从底部、左侧和右侧连接到容器,并从顶部连接到第一个文本视图。这将确保它们在设置内容时适当地拉伸。

不要对视图的高度设置任何约束,或者如果必须(以避免来自约束检查器的警告),请将其中一个视图的高度设置为 >= 20 或类似的小数字。

禁用两个文本视图的滚动、弹跳和滚动指示器。此解决方案依赖于视图是固定的、不可滚动的高度,因此如果您希望内容滚动,您应该使用 UIScrollView 或 UITableViewCell 作为容器。

在您的视图控制器文件中为您的两个新文本视图创建 outlet,将它们命名为 textView1textView2

第 2 步 - 将 textContainerInsets 设置为零:

使用用户定义的运行时属性将两个文本视图上的 textContainerInset 属性设置为零:

或代码:

self.textView1.textContainerInset = UIEdgeInsetsZero;
self.textView2.textContainerInset = UIEdgeInsetsZero;

这将确保设置内容时两个视图之间不会出现不可见的空间,并且不应影响视图周围的其他间距。

第 3 步 - 拆分内容、设置内容并更新视图高度:

只需将以下代码复制到您的视图控制器文件 (viewDidLoad) 中,并将 contentString 变量设置为您的内容。

/* Content is split across two UITextViews to avoid max drawing height */

NSString *contentString = @"Some very long piece of text...";

// Set text
NSArray *components = [contentString componentsSeparatedByString:@"\n"];
NSInteger halfLength = [components count] / 2;
NSArray *firstHalf = [components subarrayWithRange:NSMakeRange(0, halfLength)];
NSArray *secondHalf = [components subarrayWithRange:NSMakeRange(halfLength, [components count] - halfLength)];
NSString *contentString1 = [firstHalf componentsJoinedByString:@"\n"];
NSString *contentString2 = [secondHalf componentsJoinedByString:@"\n"];
self.textView1.text = contentString1;
self.textView2.text = contentString2;

// Set text view heights
CGFloat fixedWidth1 = self.textView1.frame.size.width;
CGFloat fixedWidth2 = self.textView2.frame.size.width;
CGSize newSize1 = [self.textView1 sizeThatFits:CGSizeMake(fixedWidth1, CGFLOAT_MAX)];
CGSize newSize2 = [self.textView2 sizeThatFits:CGSizeMake(fixedWidth2, CGFLOAT_MAX)];
CGRect newFrame1 = self.textView1.frame;
CGRect newFrame2 = self.textView2.frame;
newFrame1.size = CGSizeMake(fmaxf(newSize1.width, fixedWidth1), MIN(newSize1.height, 8192));
newFrame2.size = CGSizeMake(fmaxf(newSize2.width, fixedWidth2), MIN(newSize2.height, 8192));
self.textView1.frame = newFrame1;
self.textView2.frame = newFrame2;

此代码大致在中间拆分 contentString,寻找最近的换行符。如果您想将内容拆分为不同的字符,只需将上面所有出现的 \n 更改为您要拆分的任何内容。

第 4 步 - 设置容器视图高度:

将您的容器视图(scrollView、tableViewCell 等)设置为两个文本视图的高度,加上您在它们上方和下方设置的任何额外空间。

CGRect viewFrame = self.myView.frame;
viewFrame.size.height = MIN(self.textView1.frame.size.height, 8192) + MIN(self.textView2.frame.size.height, 8192) + kTextViewContainerPadding;
[self.myView setFrame:viewFrame];

(在我的代码中,kTextViewContainerPadding 是一个宏,我将它们设置为两个文本视图上方和下方的空间总和,在它们的容器内)。

就是这样!祝你好运。

【讨论】:

【参考方案3】:

尝试为scrollView启用滚动。 保持textView的高度>内容的高度,这样在现实中就不会出现滚动了,但是scrollEnabled应该是=YES

它为我解决了这个问题。

【讨论】:

【参考方案4】:

你好,我想现在回答还不晚。我遇到了和你一样的问题。这是我的解决方案:

textView.scrollEnabled = YES;    
contentTextView.attributedText = finalAttrString;
// contentTextView.text = [attrString string];
contentTextView.font = kFont(contentTextFS + [valueOfStepper intValue]);

[contentTextView sizeToFit];
contentTextView.height += 1;//This is the key code
//contentTextView.height = 8192.0f

他们我解决了问题,我可以在 iOS 8 上更改大小 dynamic.Successfull

【讨论】:

textView == contentTextView 这与提出的问题有什么关系?

以上是关于UITextView 文字在高度达到 8192.0 后变得不可见的主要内容,如果未能解决你的问题,请参考以下文章

如何根据文字长度增加 UITextview 高度,如 whatsapp

iOS UITextView 高度随文字自己主动添加,并尾随键盘移动

iosiOStextView实现文字高度自适应

UITextView 底部有更多文字和更多空白

iOS UITextView自适应高度UITextContainerView抖动问题

粘贴长文本时UITextView动态高度滚动不起作用