系统字体 "Hiragino Sans" 显示为剪裁的上升和下降
System font "Hiragino Sans" is show with clipped ascender and descenders
我需要在我的应用程序中使用 iOS 的系统字体 "Hiragino Sans W3",但无论我选择哪个 size/style 或 UILabel
的尺寸,字体的上行和下行总是被剪掉:
这似乎可以通过创建 UILabel
的子类并将方法 textRectForBounds:limitedToNumberOfLines:
覆盖为 return "correct" 值来解决。所以下面的代码...
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGRect result = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
result = CGRectInset(result, 0, -5);
return result;
}
...导致上部和下部不再被剪裁:
我知道也可以使用外部编辑器来调整字体的升序和降序位置。 但是这是系统字体,不修改不应该能正常工作吗?我在这里遗漏了什么吗?
提前感谢您的回答。
我认为这个问题归结为字体本身 ("Hiragino Sans")。使用字体编辑器可以看到字形超出了上升值和下降值,这就是 iOS 似乎假设显示文本的垂直 "bounding box"。
由于缺乏更好的解决方案,我一直在使用(非常丑陋的)技巧来修改 UIFont
read-only 属性 ascender
和 [=14= 的值].
文件UIFont+Alignment.h
:
#import <UIKit/UIKit.h>
@interface UIFont (Alignment)
- (void)ensureCorrectFontAlignment;
@end
文件UIFont+Alignment.m
:
#import "UIFont+Alignment.h"
#import <objc/runtime.h>
#import <objc/message.h>
static NSHashTable *adjustedFontsList;
@implementation UIFont (Alignment)
- (void)ensureCorrectFontAlignment
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
adjustedFontsList = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory];
});
@synchronized (adjustedFontsList) {
if ([adjustedFontsList containsObject:self]) {
return;
}
else if ([self.fontName containsString:@"Hiragino"]) {
SEL originalAscenderSelector = @selector(ascender);
Method originalAscenderMethod = class_getInstanceMethod([UIFont class], originalAscenderSelector);
SEL originalLineHeightSelector = @selector(lineHeight);
Method originalLineHeightMethod = class_getInstanceMethod([UIFont class], originalLineHeightSelector);
id result = method_invoke(self, originalAscenderMethod, nil);
CGFloat originalValue = [[result valueForKey:@"ascender"] floatValue];
[result setValue:@(originalValue * 1.15) forKey:@"ascender"];
result = method_invoke(self, originalLineHeightMethod, nil);
originalValue = [[result valueForKey:@"lineHeight"] floatValue];
[result setValue:@(originalValue * 1.25) forKey:@"lineHeight"];
[adjustedFontsList addObject:self];
}
}
}
@end
要应用,只需导入 header 并在创建新字体实例后调用 [myUIFont ensureCorrectFontAlignment]
。
帮助了我,但是我遇到了错误
Too many arguments to function call, expected 0, have 2 method_invoke
我替换了
id result = method_invoke(self, originalAscenderMethod, nil);
和
id (*function)(id, Method) = (id (*)(id, Method)) method_invoke;
id result = function(self, originalAscenderMethod);
和
result = method_invoke(self, originalLineHeightMethod, nil);
和
result = function(self, originalLineHeightMethod);
Swift 使用方法调配的版本:
extension UIFont {
static func swizzle() {
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(getter: ascender))!,
class_getInstanceMethod(self, #selector(getter: swizzledAscender))!
)
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(getter: lineHeight))!,
class_getInstanceMethod(self, #selector(getter: swizzledLineHeight))!
)
}
private var isHiragino: Bool {
fontName.contains("Hiragino")
}
@objc private var swizzledAscender: CGFloat {
if isHiragino {
return self.swizzledAscender * 1.15
} else {
return self.swizzledAscender
}
}
@objc private var swizzledLineHeight: CGFloat {
if isHiragino {
return self.swizzledLineHeight * 1.25
} else {
return self.swizzledLineHeight
}
}
}
调用 UIFont.swizzle()
一次,例如在 application(_:didFinishLaunchingWithOptions:)
.
我需要在我的应用程序中使用 iOS 的系统字体 "Hiragino Sans W3",但无论我选择哪个 size/style 或 UILabel
的尺寸,字体的上行和下行总是被剪掉:
这似乎可以通过创建 UILabel
的子类并将方法 textRectForBounds:limitedToNumberOfLines:
覆盖为 return "correct" 值来解决。所以下面的代码...
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGRect result = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
result = CGRectInset(result, 0, -5);
return result;
}
...导致上部和下部不再被剪裁:
我知道也可以使用外部编辑器来调整字体的升序和降序位置。 但是这是系统字体,不修改不应该能正常工作吗?我在这里遗漏了什么吗?
提前感谢您的回答。
我认为这个问题归结为字体本身 ("Hiragino Sans")。使用字体编辑器可以看到字形超出了上升值和下降值,这就是 iOS 似乎假设显示文本的垂直 "bounding box"。
由于缺乏更好的解决方案,我一直在使用(非常丑陋的)技巧来修改 UIFont
read-only 属性 ascender
和 [=14= 的值].
文件UIFont+Alignment.h
:
#import <UIKit/UIKit.h>
@interface UIFont (Alignment)
- (void)ensureCorrectFontAlignment;
@end
文件UIFont+Alignment.m
:
#import "UIFont+Alignment.h"
#import <objc/runtime.h>
#import <objc/message.h>
static NSHashTable *adjustedFontsList;
@implementation UIFont (Alignment)
- (void)ensureCorrectFontAlignment
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
adjustedFontsList = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory];
});
@synchronized (adjustedFontsList) {
if ([adjustedFontsList containsObject:self]) {
return;
}
else if ([self.fontName containsString:@"Hiragino"]) {
SEL originalAscenderSelector = @selector(ascender);
Method originalAscenderMethod = class_getInstanceMethod([UIFont class], originalAscenderSelector);
SEL originalLineHeightSelector = @selector(lineHeight);
Method originalLineHeightMethod = class_getInstanceMethod([UIFont class], originalLineHeightSelector);
id result = method_invoke(self, originalAscenderMethod, nil);
CGFloat originalValue = [[result valueForKey:@"ascender"] floatValue];
[result setValue:@(originalValue * 1.15) forKey:@"ascender"];
result = method_invoke(self, originalLineHeightMethod, nil);
originalValue = [[result valueForKey:@"lineHeight"] floatValue];
[result setValue:@(originalValue * 1.25) forKey:@"lineHeight"];
[adjustedFontsList addObject:self];
}
}
}
@end
要应用,只需导入 header 并在创建新字体实例后调用 [myUIFont ensureCorrectFontAlignment]
。
Too many arguments to function call, expected 0, have 2 method_invoke
我替换了
id result = method_invoke(self, originalAscenderMethod, nil);
和
id (*function)(id, Method) = (id (*)(id, Method)) method_invoke;
id result = function(self, originalAscenderMethod);
和
result = method_invoke(self, originalLineHeightMethod, nil);
和
result = function(self, originalLineHeightMethod);
Swift 使用方法调配的版本:
extension UIFont {
static func swizzle() {
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(getter: ascender))!,
class_getInstanceMethod(self, #selector(getter: swizzledAscender))!
)
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(getter: lineHeight))!,
class_getInstanceMethod(self, #selector(getter: swizzledLineHeight))!
)
}
private var isHiragino: Bool {
fontName.contains("Hiragino")
}
@objc private var swizzledAscender: CGFloat {
if isHiragino {
return self.swizzledAscender * 1.15
} else {
return self.swizzledAscender
}
}
@objc private var swizzledLineHeight: CGFloat {
if isHiragino {
return self.swizzledLineHeight * 1.25
} else {
return self.swizzledLineHeight
}
}
}
调用 UIFont.swizzle()
一次,例如在 application(_:didFinishLaunchingWithOptions:)
.