【问题标题】:AutoLayout link two UILabels to have the same font sizeAutoLayout 链接两个 UILabel 以具有相同的字体大小
【发布时间】:2013-12-14 06:10:03
【问题描述】:

我有两个 UILabel 并排排列,左右调整,如下所示。

 |-Some text left adjusted----------some other text right adjusted-|

两个标签都有 adjustsFontSizeToFitWidth = YES 并通过以下约束相互链接

[NSLayoutConstraint constraintWithItem:_rightLabel
                    attribute:NSLayoutAttributeLeft
                    relatedBy:NSLayoutRelationGreaterThanOrEqual
                    toItem:_leftLabel
                    attribute:NSLayoutAttributeRight
                    multiplier:1
                    constant:10]

这样它们就可以尽可能多地占用空间,如果没有足够的空间容纳原始字体大小,它会通过adjustsFontSizeToFitWidth 降低,这样就不会截断任何文本。

我的问题是,当一个标签由于长文本而需要降低其字体大小时,我希望另一个标签也降低其字体大小,以便两者的大小相同,而不是一个可能是另一个大小的两倍。我也想限制字体大小以匹配,但可惜我不知道该怎么做,有什么想法吗?

【问题讨论】:

  • 我设法通过在两个标签之间施加相等的宽度约束来获得想要的效果..(字体缩放在两者中是相同的,尽管最后两个字符被截断了..)跨度>

标签: ios uilabel autolayout


【解决方案1】:

您可以尝试使用key-value observing 来观察一个标签上字体属性的变化,当发生变化时,将另一个标签设置为使用相同的字体。

在您的 -viewDidLoad 方法中:

// Add self as an observer of _rightLabel's font property
[_rightLabel addObserver:self forKeyPath:@"font" options:NSKeyValueObservingOptionNew context:NULL];

在同一个控制器实现中(上面代码sn-ps上下文中的self):

// Observe changes to the font property of _rightLabel
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == _rightLabel && [keyPath isEqualToString:@"font"]) {
        // Set _leftLabel's font property to be the new value set on _rightLabel
        _leftLabel.font = change[NSKeyValueChangeNewKey];
    }
}

【讨论】:

  • 我认为使用adjustsFontSizeToFitWidth 时字体属性不会改变。 font 值保持不变,但在显示时会以较小的字体大小呈现。
  • only way to calculate the adjusted font size 在 iOS 7 中已被弃用。
【解决方案2】:

来自UILabel documentation on adjustsFontSizeToWidth

通常,标签文本是使用您在字体属性中指定的字体绘制的。但是,如果此属性设置为 YES,并且 text 属性中的文本超出标签的边界矩形,则接收器开始减小字体大小,直到字符串适合或达到最小字体大小。

由此推断,更新的字体是在绘制时计算的,font 属性只能读取,不能写入。因此,我相信 Andrew 建议在 font 属性上使用 KVO 不会奏效。

因此,为了达到您想要的效果,您需要计算调整后的字体大小。

正如 Jackson 在 cmets 中指出的那样,获取实际字体的 this very convenient NSString method 在 iOS 7 中已被弃用。从技术上讲,您仍然可以使用它,直到它被删除。

另一种选择是遍历字体比例,直到找到适合两个标签的字体。我能够让它正常工作; here's a sample project that shows how I did it.

另外,这里是链接停止工作的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_rightLabel
                                                                  attribute:NSLayoutAttributeLeft
                                                                  relatedBy:NSLayoutRelationGreaterThanOrEqual
                                                                     toItem:_leftLabel
                                                                  attribute:NSLayoutAttributeRight
                                                                 multiplier:1
                                                                   constant:10];

    [self.view addConstraint:constraint];
}

- (IBAction)makeRightLabelLongerPressed:(id)sender {
    self.rightLabel.text = @"some much longer right label text";
}

- (IBAction)adjustLabelSizes:(id)sender {
    NSLog(@"Attempting to adjust label sizes…");

    CGFloat minimumScaleFactor = fmaxf(self.rightLabel.minimumScaleFactor, self.leftLabel.minimumScaleFactor);;
    UIFont * startingFont = self.rightLabel.font;

    for (double currentScaleFactor = 1.0; currentScaleFactor > minimumScaleFactor; currentScaleFactor -= 0.05) {
        UIFont *font = [startingFont fontWithSize:startingFont.pointSize * currentScaleFactor];
        NSLog(@"  Attempting font with scale %f (size = %f)…", currentScaleFactor, font.pointSize);

        BOOL leftLabelWorks = [self wouldThisFont:font workForThisLabel:self.leftLabel];
        BOOL rightLabelWorks = [self wouldThisFont:font workForThisLabel:self.rightLabel];
        if (leftLabelWorks && rightLabelWorks) {
            NSLog(@"    It fits!");
            self.leftLabel.font = font;
            self.rightLabel.font = font;
            return;
        } else {
            NSLog(@"    It didn't fit. :-(");
        }

    }

    NSLog(@"  It won't fit without violating the minimum scale (%f), so set both to minimum.  Some text may get truncated.", minimumScaleFactor);

    UIFont *minimumFont = [self.rightLabel.font fontWithSize:self.rightLabel.font.pointSize * self.rightLabel.minimumScaleFactor];
    self.rightLabel.font = minimumFont;
    self.leftLabel.font = minimumFont;
}

- (BOOL) wouldThisFont:(UIFont *)testFont workForThisLabel:(UILabel *)testLabel {
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:testFont, NSFontAttributeName, nil];
    NSAttributedString *as = [[NSAttributedString alloc] initWithString:testLabel.text attributes:attributes];
    CGRect bounds = [as boundingRectWithSize:CGSizeMake(CGRectGetWidth(testLabel.frame), CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin) context:nil];
    BOOL itWorks = [self doesThisSize:bounds.size fitInThisSize:testLabel.bounds.size];
    return itWorks;
}

- (BOOL)doesThisSize:(CGSize)aa fitInThisSize:(CGSize)bb {
    if ( aa.width > bb.width ) return NO;
    if ( aa.height > bb.height ) return NO;
    return YES;
}

这种方法可以简单地重构为一个类别方法,以替换 Jackson 链接到的已弃用方法。

【讨论】:

  • 我不确定我是否完全理解您的情况。如果我对我的想法是正确的,也许您可​​以添加第三个标签,其中包含您所描述的两者的连接文本。新标签将是透明的,其唯一目的是建立适当的字体大小。对于标签大小。然后其他两个标签可以简单地使用与透明标签相同的字体大小进行适当的调整。
  • @VictorEngel 此代码无需制作第三个标签即可建立正确的字体大小。尝试下载并运行该项目。
  • 当然。我只是建议一个只使用自动布局的替代方案。它旨在成为对原始问题的评论,而不是对您的答案的评论。不知道它是如何在这里结束的。对此感到抱歉。
  • 有人有演示源的链接吗?谢谢
【解决方案3】:

我找到了更好的解决方案。只需将文本空间从头到尾添加到 uilabel,文本长度更短。字体也一样。

【讨论】:

  • 这让我发笑——我喜欢它的简单性,即使它不能 100% 工作。如果您的字体不是固定宽度,则空格不是大多数其他字母的保存宽度。如果您有一个带有很多“w”(非常宽)的长字符串,它仍然会比带有空格填充的短字符串长。换句话说,即使它们是相同数量的字符,它们也不总是相同的宽度。尽管在许多情况下它足够接近工作。
  • 我不敢相信...?️??️
【解决方案4】:

你可以这样解决这个问题:

斯威夫特 5

extension UILabel {
    var actualFontSize: CGFloat {
        guard let attributedText = attributedText else { return font.pointSize }
        let text = NSMutableAttributedString(attributedString: attributedText)
        text.setAttributes([.font: font as Any], range: NSRange(location: 0, length: text.length))
        let context = NSStringDrawingContext()
        context.minimumScaleFactor = minimumScaleFactor
        text.boundingRect(with: frame.size, options: .usesLineFragmentOrigin, context: context)
        let adjustedFontSize: CGFloat = font.pointSize * context.actualScaleFactor
        return adjustedFontSize
    } 
}

用法:

firstLabel.text = firstText
secondLabel.text = secondText
view.setNeedsLayout()
view.layoutIfNeeded()
let smallestSize = min(firstLabel.actualFontSize, secondLabel.actualFontSize)
firstLabel.font = firstLabel.font.withSize(smallestSize)
secondLabel.font = secondLabel.font.withSize(smallestSize)

【讨论】:

  • 它不适用于UIFont.prefferedFont 类型。它的值非常小,例如 0.1499...
猜你喜欢
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
相关资源
最近更新 更多