Menambahkan Pengetikan Kustom Dinamis ke Proyek iOS Anda — Nimble

Dec 02 2022
Pendahuluan Tipe Dinamis adalah fitur aksesibilitas di iOS dan macOS. Fitur tersebut memungkinkan pengguna untuk mengatur skala teks yang diterapkan ke seluruh perangkat, diperbarui secara otomatis.

pengantar

Dynamic Typeadalah fitur aksesibilitas di iOS dan macOS. Fitur tersebut memungkinkan pengguna untuk mengatur skala teks yang diterapkan ke seluruh perangkat, diperbarui secara otomatis. Skala bisa lebih besar dari default untuk membantu pengguna dengan kemampuan penglihatan yang lebih rendah atau lebih kecil untuk mengisi layar dengan lebih banyak data sekaligus.

Font default UIKit dan SwiftUI menyertakan fitur ini secara internal, yang harus dilakukan pengembang hanyalah mengatur font pada label dengan gaya font.

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

Menambahkan Font Kustom

Mulailah dengan memilih font yang akan digunakan dalam proyek. Dianjurkan untuk menggunakan font dengan banyak bobot untuk menyampaikan makna yang berbeda dalam aplikasi.

Font dapat diunduh dari platform gratis seperti Google Fonts .

Seret file font ke proyek Xcode. Praktik terbaiknya adalah membuat folder Fontdan subfolder untuk setiap jenis font.

Buka target utama Info.plistdan tambahkan kunci UIAppFontssebagai larik. Di dalam array, tambahkan nama file dan ekstensi untuk setiap font yang disertakan.

File font sekarang diimpor ke proyek dan dapat digunakan dengan membuat instance 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"]

Cara termudah untuk menggunakan font khusus di proyek Swift adalah dengan menetapkan font langsung ke label.

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

Menyesuaikan Ukuran Teks di iOS

Pengaturan Aksesibilitas

Luncurkan aplikasi Pengaturan di perangkat atau simulator. Arahkan ke Accessibility > Display & Text Size > Larger Text. Penggeser akan mengubah ukuran font untuk sistem.

Mengubah ukuran teks tidak akan menyebabkan aplikasi apa pun diluncurkan tetapi tata letaknya akan dibuat ulang.

⚙️ Ini untuk iOS 15, versi iOS lainnya akan memiliki sedikit perbedaan tetapi opsi harus dapat dicari dengan Text Sizeatau Larger Text.

Penggantian Lingkungan Xcode

Di Xcode, setelah berhasil menjalankan aplikasi di simulator, temukan file Debug Area. Itu Debug Areaberisi tombol dengan simbol matikan. Tombol ini akan memunculkan Environment Overridesmenu untuk simulator. Ukuran teks dapat disesuaikan dengan penggeser untuk Dynamic Type.

Environment Overridesakan mengesampingkan pengaturan simulator dan akan mengembalikan pengaturan terbaru pada simulator saat dimatikan.

Meluncurkan ulang aplikasi dengan pengaturan perangkat yang diubah harus menampilkan teks baru dalam skala baru. Namun, ukuran font tidak dapat diubah saat aplikasi sedang berjalan. Apa yang hilang adalah alat penskalaan. Ubah kode untuk menyetel teks label sebagai berikut:

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

Untuk meningkatkan UIFontMetricskemampuan, kami memperkenalkan pembantu:

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

Selain menambahkan layer lain ke UIFontMetrics, helper berfungsi sebagai gateway untuk fungsionalitas yang dapat dilakukan aplikasi. Daftar persyaratan tersebut meliputi:

  • Semua font khusus dapat digunakan dalam satu fungsi.
  • Ukuran teks dapat dibedakan berdasarkan gaya teksnya (yaitu: badan, judul, keterangan, dll.).
  • Ukuran teks dapat diganti dengan pengaturan dalam aplikasi.

Pertama, kami membuat protokol untuk memilih font: DynamicFont.

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

Contoh DynamicFontuntuk demo kami adalah sebagai berikut.

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)

Versi helper di atas dapat langsung digunakan di iOS 11. UILabelharus adjustsFontForContentSizeCategorydiatur trueuntuk mengizinkan pembaruan otomatis saat sistem mengubah ukuran teks.

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.scaledFonthanya tersedia di iOS 11 dan lebih baru. Untuk iOS 10, skala font perlu disediakan secara manual untuk setiap kategori gaya dan ukuran teks, serta memperbarui font saat ukuran teks sistem berubah.

Skala Huruf

Perkenalkan protokol baru:

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
}

Fungsi ini customFontperlu dimodifikasi untuk mengakomodasi penskalaan 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
}

Perbarui Ukuran Teks Secara Otomatis

Saat ini, aplikasi hanya akan menampilkan font yang benar saat pertama kali dimuat. Halaman perlu mengatur font untuk setiap komponen setiap kali ukuran teks berubah. Hal ini dapat dilakukan dengan mendengarkan NotificationCenternotifikasi 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)
    }
}

Untuk yang non RxSwift, jangan lupa NotificationCenter.removeObserverhubungi deinit.

Ukuran font akan diperbarui secara otomatis saat ukuran teks sistem berubah.

SwiftUI

SwiftUI memiliki pengubah tampilan khusus untuk memodifikasi font.

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

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

Memperbarui Ukuran Font

Untuk mengizinkan pembaruan ukuran font, pengubah tampilan baru akan digunakan untuk memperhitungkan perubahan ukuran teks sistem.

Jika proyek tersebut murni SwiftUI, deklarasi yang ada customFont(_ font: DynamicFont, forTextStyle style: UIFont.TextStyle, overrideFontSize: UIContentSizeCategory? = nil) -> UIFont?dapat diabaikan.

Deklarasi metode SwiftUI yang setara adalah:

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

Deklarasi ScaledFontadalah:

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

Dengan pengubah scaledFontkita dapat mengubah font pada tampilan apa pun dengan tanda tangan yang serupa. Tampilan yang dihasilkan akan memperbarui ukuran font saat pengaturan sistem berubah.

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

Implementasi saat ini ScaledFont: ViewModifiertidak termasuk mengesampingkan ukuran font dalam aplikasi.

Untuk mengizinkan pengesampingan, UIFontMetrics.scaledValue(for:, compatibleWith:)akan digunakan. Ini sama dalam UIKitimplementasinya; namun, mengonversi dari ContentSizeCategoryke UIContentSizeCategory, untuk memenuhi scaledValueinput , hanya dapat dilakukan untuk iOS 14 dan yang lebih baru.

Ubah kode untuk ScaledFont.bodymenjadi:

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

Dengan menggunakan modifier scaledFont, kita sekarang dapat mengganti ukuran teks.

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

Swift terus berkembang untuk memungkinkan penerapan aksesibilitas yang mudah guna meningkatkan kualitas hidup pengguna. Fungsi pembantu yang disajikan di blog ini dapat dengan mudah diintegrasikan ke dalam proyek yang sudah ada dan yang baru.

Font Dinamis akan memungkinkan pengguna yang kuat untuk melihat lebih banyak data dengan sekilas serta membantu pengguna dengan masalah penglihatan untuk menggunakan aplikasi dengan lancar. Font Dinamis adalah salah satu dari banyak fitur aksesibilitas yang dapat digunakan pengembang untuk meningkatkan aplikasi mereka.

Kode sumber untuk proyek ini tersedia di repositori kami .

Referensi

Menskalakan font kustom secara otomatis dengan Tipe Dinamis Cara menggunakan Tipe Dinamis dengan font kustom Tipe Dinamis Praktis

Awalnya diterbitkan di https://nimblehq.co .