Ajout de la saisie personnalisée dynamique à votre projet iOS — Nimble

Dec 02 2022
Introduction Dynamic Type est une fonctionnalité d'accessibilité sur iOS et macOS. La fonctionnalité permet à l'utilisateur de définir une échelle de texte appliquée à l'ensemble de l'appareil, mise à jour automatiquement.

Introduction

Dynamic Typeest une fonctionnalité d'accessibilité sur iOS et macOS. La fonctionnalité permet à l'utilisateur de définir une échelle de texte appliquée à l'ensemble de l'appareil, mise à jour automatiquement. L'échelle peut être plus grande que la valeur par défaut pour aider les utilisateurs ayant une capacité de vision réduite ou plus petite pour remplir l'écran avec plus de données à la fois.

La police par défaut de UIKit et SwiftUI inclut cette fonctionnalité en interne, tout ce que le développeur a à faire est de définir la police sur l'étiquette avec un style de police.

textLabel.font = .preferredFont(forTextStyle: .body)

Ajout d'une police personnalisée

Commencez par choisir une police à utiliser dans le projet. Il est conseillé d'utiliser une police avec plusieurs poids pour transmettre différentes significations dans l'application.

Les polices peuvent être téléchargées à partir d'une plateforme gratuite telle que Google Fonts .

Faites glisser les fichiers de police vers le projet Xcode. La meilleure pratique consiste à créer un dossier Fontet un sous-dossier pour chaque famille de polices.

Ouvrez la cible principale Info.plistet ajoutez la clé UIAppFontsen tant que tableau. À l'intérieur du tableau, ajoutez le nom de fichier et l'extension de chacune des polices incluses.

Les fichiers de police sont maintenant importés dans le projet et peuvent être utilisés en créant une instance de UIFont.

textLabel.font = UIFont(name: "Font-Name", size: UIFont.labelFontSize)

for family in UIFont.familyNames.sorted() {
    let names = UIFont.fontNames(forFamilyName: family)
    print("Family: \(family) Font names: \(names)")
}

// Family: Zen Old Mincho Font names: ["ZenOldMincho-Regular", "ZenOldMincho-Bold"]

Le moyen le plus simple d'utiliser une police personnalisée dans le projet Swift consiste à attribuer la police directement à l'étiquette.

textLabel.font = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)

Ajuster la taille du texte sur iOS

Paramètres d'accessibilité

Lancez l'application Paramètres sur l'appareil ou un simulateur. Accédez à Accessibility > Display & Text Size > Larger Text. Le curseur changera la taille de la police pour le système.

La modification de la taille du texte ne provoquera le lancement d'aucune application, mais la mise en page sera refaite.

⚙️ Ceci est pour iOS 15, les autres versions d'iOS auront une légère différence mais l'option devrait être consultable avec Text Sizeou Larger Text.

Remplacements de l'environnement Xcode

Sur Xcode, après avoir exécuté avec succès l'application sur un simulateur, recherchez le fichier Debug Area. Le Debug Areacontient un bouton avec le symbole de bascule. Ce bouton devrait faire apparaître le Environment Overridesmenu du simulateur. La taille du texte peut être ajustée avec le curseur pour Dynamic Type.

Environment Overridesremplacera les paramètres du simulateur et renverra les paramètres les plus récents sur le simulateur lorsqu'il est éteint.

La relance de l'application avec les paramètres de l'appareil modifiés devrait afficher le nouveau texte dans la nouvelle échelle. Cependant, il n'est pas possible de modifier la taille de la police lorsque l'application est en cours d'exécution. Ce qui manque, c'est un outil de mise à l'échelle. Modifiez le code de définition du texte de l'étiquette comme suit :

let customFont = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)!
label.font = UIFontMetrics.default.scaledFont(for: customFont)
label.adjustsFontForContentSizeCategory = true

Pour tirer parti UIFontMetricsdes capacités, nous introduisons un assistant :

func customFont(
    _ font: DynamicFont,
    forTextStyle style: UIFont.TextStyle,
    overrideFontSize: UIContentSizeCategory? = nil
) -> UIFont?

En plus d'ajouter une autre couche à UIFontMetrics, l'assistant sert de passerelle pour les fonctionnalités que l'application peut faire. La liste des exigences comprend :

  • Toutes les polices personnalisées peuvent être utilisées dans une seule fonction.
  • Les tailles de texte se distinguent par leur style de texte (c'est-à-dire : corps, titre, légende, etc.).
  • La taille du texte peut être remplacée par les paramètres de l'application.

Tout d'abord, nous créons un protocole pour choisir une police : DynamicFont.

protocol DynamicFont {
    func fontName() -> String
    func fontSize(style: UIFont.TextStyle) -> CGFloat
}

L'exemple de DynamicFontnotre démo est le suivant.

enum ZenOldMincho: DynamicFont {
    case regular
    case bold

    func fontName() -> String {
        switch self {
        case .regular: return "ZenOldMincho-Regular"
        case .bold: return "ZenOldMincho-Bold"
        }
    }

    func fontSize(style: UIFont.TextStyle) -> CGFloat {
        switch style {
        case .largeTitle: return 34.0
        case .title1: return 28.0
        case .title2: return 22.0
        case .title3: return 20.0
        case .headline: return 18.0
        case .body: return 17.0
        case .callout: return 16.0
        case .subheadline: return 15.0
        case .footnote: return 13.0
        case .caption1: return 12.0
        case .caption2: return 11.0
        default: return 17.0
        }
    }
}

extension UIFont {
    static func customFont(
        _ font: DynamicFont,
        forTextStyle style: UIFont.TextStyle,
        overrideFontSize: UIContentSizeCategory? = nil
    ) -> UIFont? {
        guard let customFont = UIFont(name: font.fontName(), size: font.fontSize(style: style)) else { return nil }
        let scaledFont: UIFont
        let metrics = UIFontMetrics(forTextStyle: style)
        return scaledFont = metrics.scaledFont(
            for: customFont, compatibleWith: UITraitCollection(
                preferredContentSizeCategory: overrideFontSize ?? .unspecified
            )
        )
    }
}

textLabel.font = .customFont(ZenOldMincho.regular, forTextStyle: .body)
overridedLabel.font = .customFont(ZenOldMincho.bold, forTextStyle: .headline, overrideFontSize: .small)

La version ci-dessus de l'assistant peut être utilisée immédiatement sur iOS 11. UILabeldevrait être adjustsFontForContentSizeCategorydéfinie truepour autoriser les mises à jour automatiques lorsque le système modifie la taille du texte.

label.adjustsFontForContentSizeCategory = true
label.font = .customFont(ZenOldMincho.regular, forTextStyle: .body)

label.adjustsFontForContentSizeCategory = false
label.font = .customFont(ZenOldMincho.regular, forTextStyle: .body, overrideFontSize: .small)

iOS 10

UIFontMetrics.scaledFontest uniquement disponible sur iOS 11 et versions ultérieures. Pour iOS 10, l'échelle de la police devra être fournie manuellement pour chaque style de texte et catégorie de taille, ainsi que la mise à jour de la police lorsque la taille du texte du système change.

Échelle de la police

Introduire un nouveau protocole :

protocol DynamicFontIOS10 {
    func font(for style: UIFont.TextStyle, sizeCategory: UIContentSizeCategory) -> UIFont?
}

extension ZenOldMincho: DynamicFontIOS10 {
    func font(for style: UIFont.TextStyle, sizeCategory: UIContentSizeCategory) -> UIFont? {
        guard let style = ZenOldMincho.fontSizeTable[style],
              let size = style[sizeCategory]
        else { return nil }
        return UIFont(name: fontName(), size: size)
    }
}

extension ZenOldMincho {
    static let fontSizeTable: [UIFont.TextStyle: [UIContentSizeCategory: CGFloat]] = [
        .headline: [
            .accessibilityExtraExtraExtraLarge: 23.0,
            .accessibilityExtraExtraLarge: 23.0,
            .accessibilityExtraLarge: 23.0,
            .accessibilityLarge: 23.0,
            .accessibilityMedium: 23.0,
            .extraExtraExtraLarge: 23.0,
            .extraExtraLarge: 21.0,
            .extraLarge: 19.0,
            .large: 17.0,
            .medium: 16.0,
            .small: 15.0,
            .extraSmall: 14.0
        ],
        .body: [
            .accessibilityExtraExtraExtraLarge: 53.0,
            .accessibilityExtraExtraLarge: 47.0,
            .accessibilityExtraLarge: 40.0,
            .accessibilityLarge: 33.0,
            .accessibilityMedium: 28.0,
            .extraExtraExtraLarge: 23.0,
            .extraExtraLarge: 21.0,
            .extraLarge: 19.0,
            .large: 17.0,
            .medium: 16.0,
            .small: 15.0,
            .extraSmall: 14.0
        ]
    // Fill with all text style
}

La fonction customFontdevra être modifiée pour s'adapter aux mises à l'échelle d'iOS 10.

static func customFont(
    _ font: DynamicFont,
    forTextStyle style: UIFont.TextStyle,
    overrideFontSize: UIContentSizeCategory? = nil
) -> UIFont? {
    guard let customFont = UIFont(name: font.fontName(), size: font.fontSize(style: style)) else { return nil }
    let scaledFont: UIFont
    if #available(iOS 11.0, *) {
        let metrics = UIFontMetrics(forTextStyle: style)
        scaledFont = metrics.scaledFont(
            for: customFont, compatibleWith: UITraitCollection(
                preferredContentSizeCategory: overrideFontSize ?? .unspecified
            )
        )
    } else {
        let sizeCategory = overrideFontSize ?? UIApplication.shared.preferredContentSizeCategory
        guard let fontIOS10 = font as? DynamicFontIOS10,
              let customFontIOS10 = fontIOS10.font(for: style, sizeCategory: sizeCategory)
        else { return customFont }
        scaledFont = customFontIOS10
    }
    return scaledFont
}

Mettre à jour automatiquement la taille du texte

Actuellement, l'application n'affichera la police correcte que lorsqu'elle sera chargée pour la première fois. La page devra définir la police pour chaque composant chaque fois que la taille du texte change. Cela peut être fait en écoutant la NotificationCenternotification de UIContentSizeCategory.didChangeNotification.

protocol DynamicFontController {

    func setUpContentSizeNotification(disposeBag: DisposeBag)
    func updateFonts(notification: Notification)
}

extension DynamicFontController where Self: UIViewController {

    func setUpContentSizeNotification(disposeBag: DisposeBag) {
        NotificationCenter.default.rx.notification(UIContentSizeCategory.didChangeNotification, object: nil)
            .withUnretained(self)
            .take(until: rx.deallocated)
            .subscribe { owner, value in
                owner.updateFonts(notification: value)
            }
            .disposed(by: disposeBag)
    }
}

Pour un non RxSwift, n'oubliez pas d'appeler NotificationCenter.removeObserverle deinit.

La taille de la police sera mise à jour automatiquement lorsque la taille du texte du système changera.

SwiftUI

SwiftUI a un modificateur de vue spécifiquement pour modifier la police.

.font(.custom(name, size: size))

Text("Hello").font(.custom("ZenOldMincho-Regular", size: 16.0))

Mise à jour de la taille de la police

Pour permettre la mise à jour de la taille de la police, un nouveau modificateur de vue sera utilisé pour tenir compte du changement de la taille du texte du système.

Si le projet est purement SwiftUI, la déclaration existante de customFont(_ font: DynamicFont, forTextStyle style: UIFont.TextStyle, overrideFontSize: UIContentSizeCategory? = nil) -> UIFont?peut être ignorée.

La déclaration d'une méthode SwiftUI équivalente est :

extension View {
    func scaledFont(
        font: DynamicFont,
        forTextStyle style: UIFont.TextStyle,
        overrideFontSize: ContentSizeCategory? = nil
    ) -> some View {
        return modifier(
            ScaledFont(
                name: font.fontName(),
                size: font.fontSize(style: style),
                overrideFontSize: overrideFontSize
            )
        )
    }
}

La déclaration de ScaledFontest :

struct ScaledFont: ViewModifier {
    @Environment(\.sizeCategory) var sizeCategory
    var name: String
    var size: CGFloat
    var overrideFontSize: ContentSizeCategory?
    func body(content: Content) -> some View {
      let scaledSize = UIFontMetrics.default.scaledValue(for: size)
      return content.font(.custom(name, size: scaledSize))
    }
}

Avec le modificateur, scaledFontnous pouvons changer la police sur n'importe quelle vue avec une signature similaire. La vue résultante mettra à jour la taille de la police à mesure que les paramètres du système changent.

Text("Hello")
  .scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline)

L'implémentation actuelle de ScaledFont: ViewModifiern'inclut pas le remplacement de la taille de la police dans l'application.

Pour autoriser le remplacement, UIFontMetrics.scaledValue(for:, compatibleWith:)sera utilisé. C'est la même chose dans UIKitla mise en œuvre; cependant, la conversion de ContentSizeCategoryvers UIContentSizeCategory, pour satisfaire scaledValuel'entrée de , n'est possible que pour iOS 14 et supérieur.

Modifiez le code pourScaledFont.body :

func body(content: Content) -> some View {
    let scaledSize = UIFontMetrics.default.scaledValue(for: size, compatibleWith: UITraitCollection(
        preferredContentSizeCategory: UIContentSizeCategory(overrideFontSize)
    ))
    return content.font(.custom(name, size: scaledSize))
}

En utilisant le modificateur scaledFont, nous pouvons maintenant remplacer la taille du texte.

Text("Hello")
  .scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline, overrideFontSize: .extraLarge)

Swift évolue en permanence pour permettre une mise en œuvre facile de l'accessibilité afin d'améliorer la qualité de vie des utilisateurs. Les fonctions d'assistance présentées dans ce blog peuvent être facilement intégrées dans des projets existants et nouveaux.

Dynamic Font permettra aux utilisateurs expérimentés de voir plus de données d'un coup d'œil et aidera les utilisateurs ayant des problèmes de vision à utiliser l'application en douceur. Dynamic Font est l'une des nombreuses fonctionnalités d'accessibilité que les développeurs peuvent adopter pour améliorer leurs applications.

Le code source de ce projet est disponible sur notre dépôt .

Références

Mise à l'échelle automatique des polices personnalisées avec Dynamic Type Comment utiliser Dynamic Type avec une police personnalisée Type dynamique pratique

Publié à l'origine sur https://nimblehq.co .