1

我有一个放入 UILabel 的标题。我让它将文本很好地包装成两行,但通常第二行只有一个小词。有没有办法告诉系统更均匀地换行?

标题是动态获取的,所以我不相信我可以提前确定。

4

4 回答 4

2

我继续创建了一个名为EvenlyWrappedLabel的 CocoaPod ,其灵感来自 Erik van der Neut 的回答。它有一些简洁的功能:

  1. 防止单个单词孤儿占据整个底线。

    例子:

    This sentence has a single
    orphan.
    

    变成:

    This sentence has
    a single orphan.
    
  2. 防止文本在顶部分组,感觉头重脚轻。

    例子:

    This sentence has a lot of words on
    the top line.
    

    变成:

    This sentence has a lot
    of words on the top line.
    
  3. 可以在可用的每一行上均匀分布文本的选项。

    例子:

    This only takes up one line.
    

    变成*:

    This only
    takes up
    one line.
    

    * numberOfLines = 3,useEveryLine = true

  4. 适用于自动布局约束并尊重内在大小。

  5. 非常容易集成,只需替换let label = UILabel()let label = EvenlyWrappedLabel().

  6. 一个糟糕的示例应用程序。

示例项目截图

如果你不使用 CocoaPods,你可以在GitHub 上找到源代码。享受!

于 2017-10-10T19:56:31.163 回答
1

您可以计算出单行的长度,然后取该宽度,除以 2,并将该结果用作 2 行标签的宽度约束。这可能会给你带来更好的视觉效果,但如果你有很长的单词会导致你的标签是 3 行(除非超过 2 行是可以的),你可能需要稍微调整一下。

这种方法的缺点是做一些额外的工作,但它可能会奏效。例如:

    NSString *text = @"这是我的很长的标题,我想均匀地放在 2 行上";
    UILabel *theLabel = [[UILabel alloc] init];
    theLabel.text = 文本;
    // ...这里的其他标签设置,如字体等
    [theLabel sizeToFit];

    CGSize 约束 = 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;
    框架大小=标签大小;
    theLabel.frame = 框架;

那应该这样做。警告:凭记忆写。:-)

于 2012-07-31T21:21:04.313 回答
1

我不相信有一种简单的方法可以做到这一点。UIKit 的附加功能NSString允许您确定显示具有特定字体的字符串所需的尺寸。您可以做的是使用所有可用宽度计算必要的高度,然后在循环中运行相同的计算,减小宽度直到它需要额外的垂直空间。然后使用之前的值作为标签的宽度并适当对齐。

于 2012-07-31T21:24:13.227 回答
0

对于多语言应用程序,我也需要修复这个完全相同的问题。该应用程序可以用 9 种不同的语言显示其 UI,并且不同语言的消息长度差异很大。正因为如此,我最终对一些多行消息进行了一些不幸的默认自动换行。例如,在某些情况下,日文翻译的结尾是一整行文本,下一行只有一两个字符。

我在我的布局实用程序类中添加了以下两种方法,为我解决了这个问题(见下面的代码)。此解决方案适用于具有任意行数(1、2、3、更多...)和任何语言的标签。(更改ECLayoutUtility为您自己的班级名称。)

基本思想是这样的:

  1. 给定一个显示文本的 UILabel,检测它的当前高度。

  2. 对不增加该高度的标签的最小宽度进行二分搜索。

while在我下面的代码中,您可以使用变量控制精度和通过循环的圈数之间的权衡granularity

此修复之前有问题的日语标签示例:

在此处输入图像描述

修复后的同一个日本标签:

在此处输入图像描述

这是我添加到布局实用程序类中的两种方法。我像这样拆分它们,因此您也可以只查询以获取新大小,以防您使用 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;
}

+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];

我已经针对不同语言的不同标签对此进行了测试,它看起来完美地完成了这项工作。这是一个越南的例子:

在此处输入图像描述

我希望这对其他人也有帮助:-)

谢谢,

埃里克

于 2016-09-09T06:44:18.930 回答