我有一个标题,我放入UILabel。我得到它将文本很好地包装到两行,但通常第二行只有一个小字。有没有办法让系统更均匀地包裹线条?
标题是动态提取的,所以我不相信我可以提前确定。
答案 0 :(得分:1)
您可以计算单行上的长度,然后取该宽度除以2,并将该结果用作2行标签的宽度约束。这可能会让你获得更好的视觉效果,但是如果你的标签长到3行(除非超过2行就可以),你可能需要稍微调整一下。
这种方法的缺点是可以做一些额外的工作,但它可能会成功。例如:
NSString *text = @"This is my very long title I want evenly on 2 lines"; UILabel *theLabel = [[UILabel alloc] init]; theLabel.text = text; // ...other label setup here, like font, etc [theLabel sizeToFit]; CGSize constraint = CGSizeMake(theLabel.frame.size.width / 2.0, 1000); CGSize labelSize = [theLabel.text sizeWithFont:theLabel.font constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; theLabel.numberOfLines = 0; theLabel.lineBreakMode = UILineBreakModeWordWrap; CGRect frame = theLabel.frame; frame.size = labelSize; theLabel.frame = frame;
应该这样做。警告:从内存写。 : - )
答案 1 :(得分:1)
我不相信有这么简单的方法。向NSString
添加了UIKit,允许您确定显示具有特定字体的字符串所需的尺寸。您可以做的是使用所有可用宽度计算所需的高度,然后在循环中运行相同的计算,减小宽度,直到它需要额外的垂直空间。然后使用前一个值作为标签的宽度并适当对齐。
答案 2 :(得分:1)
我继续创造了一个名为EvenlyWrappedLabel的CocoaPod,其灵感来自Erik van der Neut的回答。它有一些简洁的功能:
防止单个单身孤儿占据整个底线。
示例:
This sentence has a single
orphan.
变为:
This sentence has
a single orphan.
防止文字在顶部分组,感觉头重脚轻。
示例:
This sentence has a lot of words on
the top line.
变为:
This sentence has a lot
of words on the top line.
可选择在每条可用线上均匀分布文字。
示例:
This only takes up one line.
变为*:
This only
takes up
one line.
* numberOfLines = 3
,useEveryLine = true
使用autolayout约束并尊重内在大小。
非常容易整合,只需将let label = UILabel()
替换为let label = EvenlyWrappedLabel()
。
一个糟糕的屁股示例应用。
如果您不使用CocoaPods,可以在GitHub上找到源代码。享受!
答案 3 :(得分:0)
对于多语言应用程序,我也需要修复同样的问题。该应用程序可以用9种不同的语言显示其UI,并且语言之间的消息长度变化很大。因此,我最终为一些多行消息提供了一些不幸的默认自动换行。例如,有几个例子,日语翻译最后有一整行文字,后面只有一两个字符。
我在Layout Utility类中添加了以下两个方法,为我解决了这个问题(参见下面的代码)。此解决方案适用于具有任意数量的行(1,2,3,更多......)和任何语言的标签。 (将ECLayoutUtility
更改为您自己的班级名称。)
基本理念是:
如果UILabel显示文本,请检测其当前高度。
二进制搜索该标签的最小宽度,不增加该高度。
在下面的代码中,您可以通过while
循环使用granularity
变量控制精度与转弯次数之间的权衡。
此修复之前有问题的日语标签示例:
修复后的那个日本标签:
这是我添加到Layout Utility类的两种方法。我将它们拆分为这样,所以你也可以查询获得新的大小,以防你使用Autolayout,并希望使用大小信息来操纵约束而不是直接调整标签本身:
+ (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;
}
我在View Controller中的+wordWrapEvenlyTextInUILabel:forMaxWidth:
调用-viewWillLayoutSubviews
方法,如下所示:
// 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];
我已经针对不同语言的不同标签对其进行了测试,看起来它完美地完成了这项工作。这是一个越南的例子:
我希望这也有助于其他人: - )
谢谢,
埃里克