+ (void)wordWrapEvenlyTextInUILabel:(UILabel *)uiLabel
forMaxWidth:(CGFloat)maxLabelWidth
{
[ECLayoutUtility resizeView:uiLabel
toSize:[self getLabelSizeWithMinimumWidthForLabel:uiLabel
forMaxWidth:maxLabelWidth]];
}
+ (CGSize)getLabelSizeWithMinimumWidthForLabel:(UILabel *)uiLabel
forMaxWidth:(CGFloat)maxLabelWidth
{
NSLog(@"Current size for label \"%@\" is %@", uiLabel.text, NSStringFromCGSize(uiLabel.frame.size));
// Start off by determining what height the label would get for the given maximum width:
CGSize labelSize = [uiLabel.text boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName:uiLabel.font }
context:nil].size;
// Constraining the label to that height, now figure out the mimumum width for
// which this label still shows its text within that given height. We find
// that height with a binary search for the smallest label width that does
// not increment the label height.
CGFloat maxWidth = maxLabelWidth;
CGFloat testWidth = 0.5 * maxWidth;
CGFloat minWidth = 0;
CGFloat granularity = 1;
while (maxWidth > testWidth + granularity)
{
CGFloat newHeight = [uiLabel.text boundingRectWithSize:CGSizeMake(testWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName:uiLabel.font }
context:nil].size.height;
NSLog(@"H: %.2f, min W: %.2f, mid W: %.2f, max W: %.2f", newHeight, minWidth, testWidth, maxWidth);
if (newHeight > labelSize.height)
{
// Width reduction lead to height increase, so new width is too small.
// Now set the new width to mid-point between what we just tried and
// the last known acceptable width:
minWidth = testWidth; // increase the lower bound
testWidth += 0.5 * (maxWidth - testWidth); // increase width for next test
}
else
{
// Height not affected by the width reduction, so lets try to reduce it even more:
maxWidth = testWidth; // reduce the upper bound
testWidth -= 0.5 * (testWidth - minWidth); // reduce width for next test
}
}
CGSize newSize = CGSizeMake(maxWidth, labelSize.height);
NSLog(@"New size for label \"%@\" is %@", uiLabel.text, NSStringFromCGSize(newSize));
return newSize;
}
// Make sure that any text in the promo message that is wrapped over multiple lines
// is wrapped evenly, so we don't get very uneven lines that look ugly:
[ECLayoutUtility wordWrapEvenlyTextInUILabel:_promoMessageLabel
forMaxWidth:_promoMessageLabel.frame.size.width];
5条答案
按热度按时间yptwkmov1#
我继续创建了一个名为EvenlyWrappedLabel的CocoaPod,它的灵感来自Erik van der Neut的答案。它有几个简洁的特点:
1.防止单个单词孤儿占据整个底线。
示例:
变成:
1.防止文本在顶部分组,感觉头重脚轻。
示例:
变成:
1.选项可在每一行中均匀分布文本。
示例:
成为 *:
numberOfLines = 3
,useEveryLine = true
*1.使用自动布局约束并遵守固有大小。
1.非常易于集成,只需将
let label = UILabel()
替换为let label = EvenlyWrappedLabel()
即可。1.一个糟糕的屁股应用程序。
如果你不使用CocoaPods,你可以在GitHub上找到源代码。好好享受吧!
x6h2sr282#
您可以计算出单个行的长度,然后取该宽度,除以2,并将结果用作2行标签的宽度约束。这可能会给你一个更好的视觉效果,但如果你有长单词,会导致你的标签是3行(除非超过2行是可以的),你可能需要稍微调整一下。
这种方法的缺点是需要做一些额外的工作,但它可能会起到作用。例如:
应该可以了警告:根据记忆写的。:—)
kkbh8khc3#
我不相信有一个简单的方法可以做到这一点。
NSString
的UIKit附加功能允许您确定显示具有特定字体的字符串所需的尺寸。您可以使用所有可用宽度来计算所需的高度,然后在循环中运行相同的计算,减小宽度,直到需要额外的垂直空间。然后使用前一个值作为标签的宽度,并将其适当对齐。jdg4fx2g4#
对于一个多语言的应用程序,我需要这个完全相同的问题,以及修复。该应用程序可以以9种不同的语言显示其UI,并且不同语言之间的消息长度差异很大。正因为如此,我最终对一些多行消息采用了一些不幸的默认单词 Package 。例如,有几个例子,日语翻译结束时,一整行文本后面只有一个或两个字符在下一行。
我在Layout Utility类中添加了以下两个方法,为我解决了这个问题(参见下面的代码)。此解决方案适用于具有任意行数(1、2、3、更多...)和任意语言的标签。(将
ECLayoutUtility
更改为您自己的类名。)基本思想是这样的:
1.给定一个显示文本的UILLabel,检测其当前高度。
1.对标签的最小宽度进行二分搜索,以 * 不 * 增加高度。
在下面的代码中,您可以通过
granularity
变量的while
循环来控制精度和圈数之间的权衡。此修复之前有问题的日文标签示例:
修复后的相同日文标签:
这是我添加到Layout Utility类中的两个方法。我这样将它们分开,所以你也可以查询新的大小,以防你正在使用Autolayout,并希望使用大小信息来操纵约束,而不是直接调整标签本身的大小:
我在View Controller中从
-viewWillLayoutSubviews
调用+wordWrapEvenlyTextInUILabel:forMaxWidth:
方法,如下所示:我已经测试了这个不同的标签在不同的语言,它看起来是做的工作完美。这里有一个越南的例子:
我希望这对其他人也有帮助:-)
谢谢
艾瑞克
pbpqsu0x5#
从这个开始:
对此:
**杀死孤儿的设计点:**从技术上讲,该函数不会杀死孤儿(自由浮动的单词,如顶部图片中的“Soul”和“life”),但会调整每行单词以尽可能接近假设的平均长度。它假定您已经创建了一个包含文本的标签。
代码如下:
当每行的平均宽度var
meanLengthPerLine
增加时,它会在前一行中创建空间,以允许更多的单词“折叠”。如果循环被绘制出来,它将从一个类似于瘦5线标签的东西变成均匀分布的三条线。以下是正在发生的事情的一个高层次:1.计算标签文本的总宽度,就好像它是在长
UILabel
上拼写出来的。1.计算平均值(除以行数-分离函数)
1.使用平均值作为起点-这是每行的目标宽度。
1.将单词添加到行中,直到超过“均值”阈值。
1.如果它违反,则创建一个新行。
1.如果在添加所有字之后,有更多的行比
UILabel
应该有(在上面的例子中,标签需要三行),然后增加平均宽度一位并重复这个过程。这为以前被推下的单词(因为违规)现在占据了一排的位置。在上面的代码中,长度增加了一个像素meanLengthPerLine += 1.0f;
,但您可以保存一些循环并添加2或3个像素,并根据您的意愿更快地获得答案,但不太准确。1.最终,您将找到所需行数的“最紧”平均宽度。
精确计算行数这里是精确计算行数的代码,因为许多现有的解决方案基于行高或其他方法包括通过舍入/单元格的一些不准确性。这个代码更长,更烦人,但似乎成立: