UILabel 斜体字体裁剪

UILabel italic font clipping

我正在尝试解决这个问题,因为在我正在处理的应用程序中我有很多字体,因此当用户更改字体时标签的大小是动态计算的。

我遇到的问题是,如果字体是斜体,那么 UILabel 会在最后被剪掉,如下图所示:

这是我目前尝试过的方法:

由于应用程序中有很多字体,我需要动态设置标签的宽度,因此 UILabel 的子类化和在 drawFrameInRect 上添加更多点是行不通的。

这是 Github 上的示例代码。

任何 help/advice 不胜感激。

我会在您的按钮和标签上使用自动布局,以始终根据您选择标签的字体大小使其居中。

然后,删除 updateLabel 方法中的所有代码。我不确定您为什么使用 UITextview 并将爵士乐带入画面。如果您在情节提要中单击您的标签并查看属性检查器并找到 "Autoshrink" 它应该设置为 "Minimum Font Size" 而不是 "Fixed Font Size."

然后我会在您的标签上使用 NSAttributedString 来根据单击的按钮更改其大小和字体。

我下载了您的 GitHub 项目,看来 UILabel 和 UITextField 计算文本边界的方式肯定不同。因此,我首先尝试将 UITextField 上的 sizeToFit 的结果大小分配给 UILabel 的大小。但是,这种方法不适用于 Strato 字体。

在尝试了其他一些失败的方法之后,我记得斜体字体的角度大致相同。字体的斜体版本通常会按与原始宽度相同的比例增加边界框的宽度。

更新:

因此,您应该能够从斜体字符串的宽度和字体大小中推导出其宽度。我在你的项目中尝试过这种方法,它适用于你列出的所有字体。我使用了以下公式:

CGRect calculatedRect = [attributedString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin) context:nil];

calculatedRect.size.width = calculatedRect.size.width + (label.font.pointSize * 0.2);

由于这取决于斜体增加的宽度,斜体加粗字体,如Strata,对宽度的影响较大。

显然,如果文本 API 得到扩充以包括可靠的文本宽度计算,您将能够采用它。但是,如果您想要向后兼容,我提出的解决方法可能仍然是更好的选择。

希望对您有所帮助!

即使我没有时间测试它,我也很确定问题出在标签尺寸是根据预付款计算的。前进是从一个角色的基点到下一个角色的移动量。通常对于斜体字体,advance 可以小于边界。因此添加预付款将切断布局的末尾。

即巴斯克维尔斜体 H:

(lldb) p bounds[0].size
(CGSize)  = (width=33.53515625, height=26.484375)
(lldb) p advances[0]
(CGSize)  = (width=30, height=0)

所以我认为如果文本以理想的方式布局(无压缩等),则必须添加最后一个字符的前进框和边界框之间的区别。

要获得这两个值,您必须调用一些 CT 函数:

// What you probably have
CTFontRef font = …;
CFStringRef string = …;
CFAAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes);

// Get the character and glyph
CFIndex count = CFStringGetLength(string); // The length of the string
UniChar character;
CFStringGetCharacters( string, CFMakeRange( count-1, 1), &character );
CGGlyph glyph;
CTStringGetGlyphsForCharacters( font, &character, &glyph,1  );

// Get the advance
CGSize advance;
CTFontGetAdvancesForGlyphs( font, 0, &glyph, &advance, 1);

// Get the bounds
CGRect bounds;
CTFontGetAdvancesForGlyphs( font, 0, &glyph, &bounds, 1);

在 Safari 中输入。

补充:你左边有同样的问题:向大写L前进是0(第一个字符),但是bounding box有一个负x。因此,左侧被剪裁。也在那里添加 space..(到目前为止更容易。)

boundingRectWithSize:options:context: 中使用 NSStringDrawingUsesDeviceMetrics 会取得更好的效果。

CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0f]}];
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));

并根据 adjustedSize.Hope 更新标签的宽度和高度

1: 使用您当前选择的字体将文本设置为您的标签。

2: 使用此方法

- (CGSize)getSizeforController:(id)view 
{
    UILabel *tempView =(UILabel *)view;
    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
    context.minimumScaleFactor = 0.8;
    float height = tempView.frame.size.height;
    CGSize size=[tempView.text boundingRectWithSize:CGSizeMake(2000, height)options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName : tempView.font}context:context].size;
    return size;
}

3: 然后设置

CGSize newSize = [self.getSizeforController:self.lblYourLabel];
self.lblYourLabel.frame.size = newSize;

希望这对你有用。

试试这个

CGSize lableWidth = CGSizeMake(300, CGFLOAT_MAX);
CGSize requiredSize = [yourLabel sizeWithFont:[UIFont fontWithName:@"FontName" size:17] constrainedToSize:lableWidth lineBreakMode:NSLineBreakByWordWrapping];
int calculatedHeight = requiredSize.height;

这对我有用。

func labelThatFits(_ title: String) -> UILabel {
    let titleLabel = UILabel()
    titleLabel.font = UIFont(name: fontName, size: 20)
    titleLabel.text = title
    titleLabel.textAlignment = .center
    titleLabel.widthAnchor.constraint(equalToConstant: titleLabel.intrinsicContentSize.width + 10).isActive = true
    return titleLabel
}