微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Swift 3 / iOS10中使用Dynamic Type和自定义字体的更好方法

我试过两种方法

方法1:

label.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
label.adjustsFontForContentSizeCategory = true

即使在“设置”中更改了首选文本大小,文本大小也会自动更改,即使在我返回应用程序之前,这也可以正常工作.但它只适用于系统字体(旧金山).

方法2:

要使用自定义字体,我向UIFontDescriptor添加一个扩展:

//from this answer https://stackoverflow.com/a/35467158/2907715
extension UIFontDescriptor {

    private struct SubStruct {
        static var preferredFontName: String = "Avenir-medium"
    }

    static let fontSizeTable : NSDictionary = [
        UIFontTextStyle.headline: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 23,UIContentSizeCategory.accessibilityExtraExtraLarge: 23,UIContentSizeCategory.accessibilityExtraLarge: 23,UIContentSizeCategory.accessibilityLarge: 23,UIContentSizeCategory.accessibilityMedium: 23,UIContentSizeCategory.extraExtraExtraLarge: 23,UIContentSizeCategory.extraExtraLarge: 21,UIContentSizeCategory.extraLarge: 19,UIContentSizeCategory.large: 17,UIContentSizeCategory.medium: 16,UIContentSizeCategory.small: 15,UIContentSizeCategory.extraSmall: 14
        ],UIFontTextStyle.subheadline: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 21,UIContentSizeCategory.accessibilityExtraExtraLarge: 21,UIContentSizeCategory.accessibilityExtraLarge: 21,UIContentSizeCategory.accessibilityLarge: 21,UIContentSizeCategory.accessibilityMedium: 21,UIContentSizeCategory.extraExtraExtraLarge: 21,UIContentSizeCategory.extraExtraLarge: 19,UIContentSizeCategory.extraLarge: 17,UIContentSizeCategory.large: 15,UIContentSizeCategory.medium: 14,UIContentSizeCategory.small: 13,UIContentSizeCategory.extraSmall: 12
        ],UIFontTextStyle.body: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 53,UIContentSizeCategory.accessibilityExtraExtraLarge: 47,UIContentSizeCategory.accessibilityExtraLarge: 40,UIContentSizeCategory.accessibilityLarge: 33,UIContentSizeCategory.accessibilityMedium: 28,UIFontTextStyle.caption1: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 18,UIContentSizeCategory.accessibilityExtraExtraLarge: 18,UIContentSizeCategory.accessibilityExtraLarge: 18,UIContentSizeCategory.accessibilityLarge: 18,UIContentSizeCategory.accessibilityMedium: 18,UIContentSizeCategory.extraExtraExtraLarge: 18,UIContentSizeCategory.extraExtraLarge: 16,UIContentSizeCategory.extraLarge: 14,UIContentSizeCategory.large: 12,UIContentSizeCategory.medium: 11,UIContentSizeCategory.small: 11,UIContentSizeCategory.extraSmall: 11
        ],UIFontTextStyle.caption2: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 17,UIContentSizeCategory.accessibilityExtraExtraLarge: 17,UIContentSizeCategory.accessibilityExtraLarge: 17,UIContentSizeCategory.accessibilityLarge: 17,UIContentSizeCategory.accessibilityMedium: 17,UIContentSizeCategory.extraExtraExtraLarge: 17,UIContentSizeCategory.extraExtraLarge: 15,UIContentSizeCategory.extraLarge: 13,UIContentSizeCategory.large: 11,UIFontTextStyle.footnote: [
            UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 19,UIContentSizeCategory.accessibilityExtraExtraLarge: 19,UIContentSizeCategory.accessibilityExtraLarge: 19,UIContentSizeCategory.accessibilityLarge: 19,UIContentSizeCategory.accessibilityMedium: 19,UIContentSizeCategory.extraExtraExtraLarge: 19,UIContentSizeCategory.extraExtraLarge: 17,UIContentSizeCategory.extraLarge: 15,UIContentSizeCategory.large: 13,UIContentSizeCategory.medium: 12,UIContentSizeCategory.small: 12,]

    final class func preferredDescriptor(textStyle: String) -> UIFontDescriptor {

        let contentSize = UIApplication.shared.preferredContentSizeCategory
        let style = fontSizeTable[textStyle] as! NSDictionary
        return UIFontDescriptor(name: SubStruct.preferredFontName,size: CGFloat((style[contentSize] as! NSNumber).floatValue))
    }

}

并在viewDidLoad()中:

label.font = UIFont(descriptor: UIFontDescriptor.preferredDescriptor(textStyle: UIFontTextStyle.body.rawValue),size: 0)
NotificationCenter.default.addobserver(self,selector:#selector(self.userChangedTextSize(notification:)),name: NSNotification.Name.UIContentSizeCategoryDidChange,object: nil)

这是userChangedTextSize函数

func userChangedTextSize(notification: NSNotification) {
    label.font = UIFont(descriptor: UIFontDescriptor.preferredDescriptor(textStyle: UIFontTextStyle.body.rawValue),size: 0)
}

方法的问题是文本大小在用户返回应用程序之前不会更改,然后用户会看到旧文本大小更改为新大小,这是不理想的.

我可以充分利用这两个世界:自定义字体的大小会在后台自动更改吗?

The problem with this method is that the text size won’t change until the user goes back to the app,and then the user would see the old text size change to the new size,which is not ideal.

分享你的想法,这可能是一个更好的用户体验,但我想你有点过分思考它.

如果您查看系统提供的应用程序(例如联系人),您将清楚地看到在用户返回应用程序之前不会进行刷新.

顺便说一下,你可以为Swift 3重构一下你的代码

extension UIFontDescriptor {

    private struct SubStruct {
        static var preferredFontName: String = "Avenir-medium"
    }

    static let fontSizeTable: [UIFontTextStyle: [UIContentSizeCategory: CGFloat]] = [
        .headline: [
            .accessibilityExtraExtraExtraLarge: 23,.accessibilityExtraExtraLarge: 23,.accessibilityExtraLarge: 23,.accessibilityLarge: 23,.accessibilityMedium: 23,.extraExtraExtraLarge: 23,.extraExtraLarge: 21,.extraLarge: 19,.large: 17,.medium: 16,.small: 15,.extraSmall: 14
        ],.subheadline: [
            .accessibilityExtraExtraExtraLarge: 21,.accessibilityExtraExtraLarge: 21,.accessibilityExtraLarge: 21,.accessibilityLarge: 21,.accessibilityMedium: 21,.extraExtraExtraLarge: 21,.extraExtraLarge: 19,.extraLarge: 17,.large: 15,.medium: 14,.small: 13,.extraSmall: 12
        ],.body: [
            .accessibilityExtraExtraExtraLarge: 53,.accessibilityExtraExtraLarge: 47,.accessibilityExtraLarge: 40,.accessibilityLarge: 33,.accessibilityMedium: 28,.caption1: [
            .accessibilityExtraExtraExtraLarge: 18,.accessibilityExtraExtraLarge: 18,.accessibilityExtraLarge: 18,.accessibilityLarge: 18,.accessibilityMedium: 18,.extraExtraExtraLarge: 18,.extraExtraLarge: 16,.extraLarge: 14,.large: 12,.medium: 11,.small: 11,.extraSmall: 11
        ],.caption2: [
            .accessibilityExtraExtraExtraLarge: 17,.accessibilityExtraExtraLarge: 17,.accessibilityExtraLarge: 17,.accessibilityLarge: 17,.accessibilityMedium: 17,.extraExtraExtraLarge: 17,.extraExtraLarge: 15,.extraLarge: 13,.large: 11,.footnote: [
            .accessibilityExtraExtraExtraLarge: 19,.accessibilityExtraExtraLarge: 19,.accessibilityExtraLarge: 19,.accessibilityLarge: 19,.accessibilityMedium: 19,.extraExtraExtraLarge: 19,.extraExtraLarge: 17,.extraLarge: 15,.large: 13,.medium: 12,.small: 12,.extraSmall: 12
        ]
    ]

    final class func preferredDescriptor(textStyle: UIFontTextStyle) -> UIFontDescriptor {
        let contentSize = UIApplication.shared.preferredContentSizeCategory
        let style = fontSizeTable[textStyle]!
        return UIFontDescriptor(name: SubStruct.preferredFontName,size: style[contentSize]!)
    }
}

无需转换为NSDictionary或NSNumber并间接获取floatValue.

这样,您的呼叫站点可以使用以下更易读的代码

func userChangedTextSize(notification: NSNotification) {
    label.font = UIFont(descriptor: .preferredDescriptor(textStyle: .body),size: 0)

}

编辑:当我正在进行同样的工作时,我将上述(在常见的解决方案中)改进为更容易的方式.

import UIKIt

extension UIFont {

    private struct CustomFont {
        static var fontFamily = "Avenir"
    }

    /// Returns a bold version of `self`
    public var bolded: UIFont {
        return fontDescriptor.withSymbolicTraits(.traitBold)
            .map { UIFont(descriptor: $0,size: 0) } ?? self
    }

    /// Returns an italic version of `self`
    public var italicized: UIFont {
        return fontDescriptor.withSymbolicTraits(.traitItalic)
            .map { UIFont(descriptor: $0,size: 0) } ?? self
    }

    /// Returns a scaled version of `self`
    func scaled(scaleFactor: CGFloat) -> UIFont {
        let newDescriptor = fontDescriptor.withSize(fontDescriptor.pointSize * scaleFactor)
        return UIFont(descriptor: newDescriptor,size: 0)
    }

    class func preferredCustomFont(forTextStyle textStyle: UIFontTextStyle) -> UIFont {
        // we are using the UIFontDescriptor which is less expensive than creating an intermediate UIFont
        let systemFontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle)

        let customFontDescriptor = UIFontDescriptor.init(fontAttributes: [
            UIFontDescriptorFamilyAttribute: CustomFont.fontFamily,UIFontDescriptorSizeAttribute: systemFontDescriptor.pointSize // use the font size of the default dynamic font
        ])

        // return font of new family with same size as the preferred system font
        return UIFont(descriptor: customFontDescriptor,size: 0)
    }

}

用法

func userChangedTextSize(notification: NSNotification) {
    label.font = UIFont.preferredCustomFont(forTextStyle: .headline)
    // or in Bold / Italic:
    // label.font = UIFont.preferredCustomFont(forTextStyle: .headline).bolded
    // label.font = UIFont.preferredCustomFont(forTextStyle: .headline).italicized
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐