系统字体" Hiragino Sans"显示与剪切上升和下降

时间:2017-06-05 17:25:19

标签: ios uilabel uifont

我需要使用iOS的系统字体" Hiragino Sans W3"在我的应用中,但无论我选择哪种尺寸/样式或UILabel尺寸,字体的上升和下降始终会被剪裁:

enter image description here

这似乎可以通过创建UILabel的子类并覆盖方法textRectForBounds:limitedToNumberOfLines:来修复"更正"值。所以下面的代码......

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
    CGRect result = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
    result = CGRectInset(result, 0, -5);
    return result;
}

...导致ascender和descenders不再被剪裁:

enter image description here

我知道也可以使用外部编辑器调整字体上升和下降位置。 但这是一个系统字体,如果没有任何修改,它是否应该正常工作?我在这里找不到什么东西?

提前感谢您的任何答案。

3 个答案:

答案 0 :(得分:1)

我认为这个问题实际上归结为字体本身(“Hiragino Sans”)。使用字体编辑器可以看到字形超出了上升和下降值,iOS似乎将其视为显示文本的垂直“边界框”。

由于缺乏更好的解决方案,我一直在使用(非常丑陋)黑客修改UIFont只读属性ascenderlineHeight的值。

档案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

要应用,只需导入标题并在创建新的字体实例后调用[myUIFont ensureCorrectFontAlignment]

答案 1 :(得分:1)

@DPR 's answer帮助了我,但我遇到了错误

  

函数调用的参数过多,应为0,有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);

答案 2 :(得分:1)

使用方法刷新的快速版本:

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:)