缩放文本以适合 iPhone
我在确定在应用程序中呈现文本的“最佳”方法时遇到了一些麻烦。
我的主视图由文本视图组成,应用程序的设计规定了一些事情:
- 文本的(字体)大小应该是动态的
- 文本框架应该在视图中垂直居中 连
- 字符应该是自动的,并且仅在需要时(如果可能的话,避免)
目前,我正在使用 UILabel 和以下代码来尝试猜测用于文本量的最佳字体大小:
txt = @"this is just some sample text";
mylabel.font = [self getFontForString:txt];
mylabel.adjustsFontSizeToFitWidth = YES;
mylabel.numberOfLines = 0;
[mylabel setText:txt];
并且:
- (UIFont *) getFontForString:(NSString *)txt {
CGFloat textLength = txt.length;
CGFloat maxFontSize = 71;
CGFloat minFontSize = 27;
CGFloat newFontSize = 0;
NSArray *chunks = [txt componentsSeparatedByString:@" "];
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"length" ascending:NO] autorelease];
NSArray *sortedChunks = [chunks sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
CGSize labelSize = theThingLabel.bounds.size;
CGSize projectedSize = [[sortedChunks objectAtIndex:0] sizeWithFont:[UIFont boldSystemFontOfSize:maxFontSize]];
if (projectedSize.width > labelSize.width) {
CGFloat percentageDifference = ((projectedSize.width - labelSize.width)/labelSize.width)*100;
if (percentageDifference > 50) {
newFontSize = ((minFontSize/percentageDifference)*100) - 10;
if (newFontSize < minFontSize) newFontSize = minFontSize;
} else {
newFontSize = ((percentageDifference/maxFontSize)*100) - 10;
if(newFontSize < (maxFontSize/2)) newFontSize = maxFontSize - abs(newFontSize);
}
} else {
if ( textLength > 11 && textLength < 255) {
newFontSize = (maxFontSize - ((maxFontSize - minFontSize) * ((textLength- 11) / 100)));
} else if (textLength <= 11) {
newFontSize = maxFontSize;
} else if (textLength >= 255) {
newFontSize = minFontSize;
}
}
return [UIFont boldSystemFontOfSize:newFontSize];
}
这在一定程度上有效,但当文本是长一点,这两个示例显示它渲染以下字符串:
- “短文本量”
- “我仍然想很好地渲染的相当长的文本量”。
正如您在第二个示例(文本更长)中看到的,存在许多问题
- :
- 掉落的 y
- 失踪的“很好”。
因此,考虑到所有这些,我的选择是什么,如果这是正确的解决方案,我愿意转向使用 coretext,但不知道从哪里开始,也有可能我犯了一个我只能做的错误在我的“字体大小猜测”代码中看不到。
I'm having a bit of trouble working out the "best" way to render text in my application.
My main view consists of a text view, and the design of the application dictates a few things:
- The (font) size of the text should be dynamic
- The text frame should be centred vertically in the view
- Hyphenation should be automatic and only when needed (avoided if possible)
At the moment i'm using a UILabel and the following code to try and guess the best font size to use for the amount of text:
txt = @"this is just some sample text";
mylabel.font = [self getFontForString:txt];
mylabel.adjustsFontSizeToFitWidth = YES;
mylabel.numberOfLines = 0;
[mylabel setText:txt];
And:
- (UIFont *) getFontForString:(NSString *)txt {
CGFloat textLength = txt.length;
CGFloat maxFontSize = 71;
CGFloat minFontSize = 27;
CGFloat newFontSize = 0;
NSArray *chunks = [txt componentsSeparatedByString:@" "];
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"length" ascending:NO] autorelease];
NSArray *sortedChunks = [chunks sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
CGSize labelSize = theThingLabel.bounds.size;
CGSize projectedSize = [[sortedChunks objectAtIndex:0] sizeWithFont:[UIFont boldSystemFontOfSize:maxFontSize]];
if (projectedSize.width > labelSize.width) {
CGFloat percentageDifference = ((projectedSize.width - labelSize.width)/labelSize.width)*100;
if (percentageDifference > 50) {
newFontSize = ((minFontSize/percentageDifference)*100) - 10;
if (newFontSize < minFontSize) newFontSize = minFontSize;
} else {
newFontSize = ((percentageDifference/maxFontSize)*100) - 10;
if(newFontSize < (maxFontSize/2)) newFontSize = maxFontSize - abs(newFontSize);
}
} else {
if ( textLength > 11 && textLength < 255) {
newFontSize = (maxFontSize - ((maxFontSize - minFontSize) * ((textLength- 11) / 100)));
} else if (textLength <= 11) {
newFontSize = maxFontSize;
} else if (textLength >= 255) {
newFontSize = minFontSize;
}
}
return [UIFont boldSystemFontOfSize:newFontSize];
}
This works, to an extent, but often falls over when the text is a bit on the long side, these two example show it rendering the following strings:
- "short amount of text"
- "a substantially longer amount of text which i still want to render nicely."
As you can see in the second example (with far longer text) there are a number of issues:
- The initial widow
- The dropped y
- The missing "nicely."
So with all this in mind, what are my options, I'm open to moving to using coretext if this is the right solution, but have no idea where to start, it's also possible I've made a mistake which I just can't see in my "font size guessing" code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
以下方法将使用 full 来获取特定矩形(区域)的特定字符串的字体大小。
使用它并获取字体大小并分配给标签。
The following method will be use full to get the font size for specific string for specific rectangle (area).
Use this and get the font size and assign to the label.
我发现有用的一件事是一个小函数,它接受一个 NSString、一个 UIFont 和一个 CGSize,返回一个 CGFloat 表示该字符串的最大字体大小,该字符串适合传递的 CGSize - 它使用
sizeWithFont
连续较小的点大小,直到返回的大小适合 CGSize 参数。如果您不关心一维,您可以将CGFLOAT_MAX
作为 x 或 y 传递,例如当您检查一条线的宽度并稍后检查整个字符串的高度时。当然,您可以定义最大和最小字体大小。我首先使用
componentsSeparatedByString
将字符串分隔成单词数组。当所有单词都以相同的字体大小呈现时,您可能想要定义一个可以连字符连接的单词,该单词是下一个最大单词的某个倍数,因此您可以为任意字体大小创建该数组,并且有一个匹配的数组相对宽度(或者可能是字典,其中单词是键,宽度是值)。在继续之前,您需要扫描任何此类单词并将其分成两个单词(一个包含连字符)。接下来,您需要使用上面提到的函数找到所有单词都适合您的大小限制的字体大小,在您显示的示例中是宽度。当候选字体大小已知时,您会检查其他约束,例如寡妇 - 可能您根据它们可能不会出现的位置(一个的开始)以及形成寡妇的线宽比例来定义这些约束。如果您发现问题,您可以组合数组中的单词以删除寡妇并重新计算新的候选字体大小 - 这样做可能会导致您最终在第一行上使用连字符或整体上使用较小的字体,但如果您的文本是“不成比例”长开始一组小词”那么你可能别无选择。
“很好地”消失的问题并不难,您只需要仔细检查渲染文本的高度 - 一旦您完成了上述过程,您可能可以使用
sizeWithFont:constrainedToSize
最后检查。如果失败,请减小最大候选字体大小并重新开始。所以:
这只是一个开始,但从那里开始应该是可行的。
One thing I have found useful is a little function that takes a NSString, a UIFont and a CGSize, returning a CGFloat representing the largest font size for that string that will fit in the CGSize passed - it uses
sizeWithFont
on successively smaller point sizes until the size returned fits within the CGSize argument. You can passCGFLOAT_MAX
as either x or y if you don't care about one dimension, like when you are checking width of a line and will check height later on the whole string. You define max and min font sizes of course.I would begin by separating the string into an array of words using
componentsSeparatedByString
. Possibly you want to define a word that may be hyphenated as a word that is some multiple of the next largest word when all words are rendered at the same font size, so you create that array for some arbitrary font size and you have a matching array of relative widths (or maybe a dictionary where the word is the key and the width the value). You need to scan for and separate any such word(s) into two words (one containing the hyphen) before proceeding. Next you need to find the font size at which all the words fit into your size constraint, in the example you have shown that is width, using the function mentioned above.When the candidate font size is known you check for your other constraints such as widows - probably you define these in terms of the positions they may not occur (the start for one) and the proportion of line width that makes a widow. If you find a problem you combine words in the array to remove the widow and recalculate a new candidate font size - doing this might cause you to end up with hyphenation on the first line or a smaller font overall but if your text is "a disproportionally long start to a group of small words" then you may have no choice.
The problem of "nicely" disappearing isn't so hard, you just need to double-check the height of the rendered text - probably you could use
sizeWithFont:constrainedToSize
once you have completed the procedures above as your final check. If it fails, reduce maximum candidate font size and start over.So:
It's only a start but it should be workable from there.