Frage Eine bessere Möglichkeit, den dynamischen Typ in Swift 3 / iOS10 mit einer benutzerdefinierten Schriftart zu verwenden


Ich habe es auf zwei Arten versucht:

Methode 1:

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

Dies funktioniert gut, auch wenn die bevorzugte Textgröße in den Einstellungen geändert wird, ändert sich die Textgröße automatisch, sogar bevor ich zurück zur App gehe. Aber Es funktioniert nur mit der Systemschrift (San Francisco).

Methode 2:

Um eine benutzerdefinierte Schriftart zu verwenden, füge ich eine Erweiterung hinzu UIFontDescriptor:

//from this answer http://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,
            UIContentSizeCategory.extraExtraExtraLarge: 23,
            UIContentSizeCategory.extraExtraLarge: 21,
            UIContentSizeCategory.extraLarge: 19,
            UIContentSizeCategory.large: 17,
            UIContentSizeCategory.medium: 16,
            UIContentSizeCategory.small: 15,
            UIContentSizeCategory.extraSmall: 14
        ],
        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,
            UIContentSizeCategory.medium: 11,
            UIContentSizeCategory.small: 11,
            UIContentSizeCategory.extraSmall: 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,
            UIContentSizeCategory.extraSmall: 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))
    }

}

und in 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)

Hier ist das userChangedTextSize Funktion:

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

Das Problem Bei dieser Methode ändert sich die Textgröße erst, wenn der Benutzer zur App zurückkehrt, und dann sieht der Benutzer die Änderung der alten Textgröße auf die neue Größe, was nicht ideal ist.

Könnte ich das Beste aus beiden Welten haben: eine benutzerdefinierte Schrift mit einer Größe, die sich automatisch im Hintergrund ändert?


5
2018-01-23 01:31


Ursprung


Antworten:


Das Problem bei dieser Methode besteht darin, dass sich die Textgröße nicht ändert, bis der Benutzer zur App zurückkehrt, und dann sieht der Benutzer, dass die alte Textgröße auf die neue Größe geändert wird, was nicht ideal ist.

Ich teile Ihre Gedanken, dass dies wahrscheinlich eine bessere UX wäre, aber ich denke, Sie überdenken es ein wenig.

Wenn Sie die vom System bereitgestellten Apps (z. B. Kontakte) sehen, werden Sie deutlich sehen, dass Die Aktualisierung wird erst durchgeführt, wenn der Benutzer zur App zurückkehrt, auch.

Übrigens könnten Sie Ihren Code ein wenig für Swift 3 umgestalten:

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,
            .extraExtraExtraLarge: 23,
            .extraExtraLarge: 21,
            .extraLarge: 19,
            .large: 17,
            .medium: 16,
            .small: 15,
            .extraSmall: 14
        ],
        .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,
            .medium: 11,
            .small: 11,
            .extraSmall: 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]!)
    }
}

Keine Notwendigkeit, zu werfen NSDictionary oder NSNumber und hol die floatValue indirekt.

Auf diese Weise kann Ihre Aufrufseite den folgenden, besser lesbaren Code verwenden:

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

}

Edit: Da ich gerade an der gleichen Stelle arbeite, habe ich die obige (auf SO häufig gesehene Lösung) etwas einfacher gemacht.

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

}

Verwendung

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
}

13
2018-02-14 20:05