给定字体的字符串长度以适合UITextView

我需要将用户输入的大型多行UITextView文本移动到较小的(但仍然是多行的) UITextView *中。 如果用户输入的文本多于在较小视图中显示的文本,我想截断文本,使其适合所有可见的(截断的)文本。 (大型UITextView和较小的UITextView都不应该滚动。)

最好的方法是什么?

我可以使用循环,每次都用字符缩短字符串,然后使用NSStringsizeWithFont: constrainedToSize: lineBreakMode:找出这个较短字符串所需的高度,然后将其与我在我的可用高度进行比较较小的UITextView ,当字符串适合时结束循环 – 但这看起来很慢而且很尴尬。 一定会有更好的办法。

我想告诉目的地UITextView截断它的displayText成员,因为它在屏幕上显示它,但我无法找到一种方法来做到这一点。

*更多关于此的背景,来自我在下面做出的评论:

我有一个风景应用程序。 我根据用户选择的照片更改视图的布局。 如果它是风景照片,则标题较小 – 只是照片底部的一条线。 如果她选择一张肖像照片,那么我可以使用足够的空间放置照片侧面的标题,因此标题更大。

如果用户将照片方向从纵向更改为横向,那么我想截断文本,然后允许她编辑它以使其有意义。 我可以摧毁它,但我宁愿保留它以减少她的打字。

我编写了以下递归方法和公共API来正确执行此操作。 丑陋的软糖因素是这个问题的主题。

 #define kFudgeFactor 15.0 #define kMaxFieldHeight 9999.0 // recursive method called by the main API -(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax { if ((aMax-aMin) <= 1) { NSString* subString = [aString substringToIndex:aMin]; return subString; } int mean = (aMin + aMax)/2; NSString* subString = [aString substringToIndex:mean]; CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight); CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap]; if (stringSize.height <= self.frame.size.height) return [self sizeStringToFit:aString min:mean max:aMax]; // too small else return [self sizeStringToFit:aString min:aMin max:mean];// too big } -(NSString*)sizeStringToFit:(NSString*)aString { CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight); CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap]; // if it fits, just return if (stringSize.height < self.frame.size.height) return aString; // too big - call the recursive method to size it NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]]; return smallerString; } 

这实际上不是一个修复,但它确实为计算提供了良好的起点。

如果你使用NSString的sizeWithFont: constrainedToSize: lineBreakMode:你得到文本的垂直高度。 如果按字体的前导高度除以该值,则得到整个字符串中的行数。 将[NSString count]除以该数字可以得出每行字符数的近似值。 这假设字符串是同质的,并且如果某人键入(例如)’iiiiiiiiiii ……’选择“MMMMMMMMM …”则将是不准确的。

您还可以使用相关字体的leading高度划分边界框,以获得适合您的边界框的行数。

每行乘以行数的字符为您提供了查找适合的文本的起点。

您可以通过对那些’iiiiii …’和“MMMMMM …’”字符串进行相同的计算来计算此图中的误差范围。

我建议采用略有不同的方法,看看你是否可以使用UILabel而不是较小的UITextView。

UILabels可以通过其numberOfLines属性设置为多行,就像UITextView一样。

UILabels也有一个lineBreakMode属性,我相信该属性的默认值将执行您正在寻找的精确截断效果。

我认为Jonathan对UILabel有所了解……

因此,用户完成编辑UITextView后,您将获得文本字符串并将其传递给UILabel。 您将UITextView的alpha更改为0和/或将其从superview中删除。 可能将未截断的全文存储在ivar中。

UILabel不是“可编辑的”,但您可以使用UILabel(或它的超级视图)检测到触摸。 当您检测到UILabel上的触摸时,您只需恢复隐藏的UITextView并恢复您保存的字符串。

有时SDK很痛苦,但它几乎总能赢得战斗。 很多时候,最好根据UIKit惯例调整您的设计