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

时间:2009-05-12 09:01:59

标签: iphone ios cocoa-touch

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

最好的方法是什么?

我可以使用循环,每次都用字符缩短字符串,然后使用sizeWithFont: constrainedToSize: lineBreakMode:的{​​{1}}找出这个较短字符串所需的高度,然后将其与高度我可以在我较小的UITextView中使用,当字符串适合时结束循环 - 但这看起来很慢而且很尴尬。必须有更好的方法。

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

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

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

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

4 个答案:

答案 0 :(得分:3)

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

#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;   
}

答案 1 :(得分:2)

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

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

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

每行乘以行数可以为找到适合的文本提供一个起点。

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

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

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

有时SDK很痛苦,但它几乎总能赢得战斗。很多时候,最好将您的设计调整为UIKit约定