Adición de escritura personalizada dinámica a su proyecto de iOS: Nimble

Introducción
Dynamic Type
es una función de accesibilidad en iOS y macOS. La función le permite al usuario establecer una escala de texto que se aplica a todo el dispositivo y se actualiza automáticamente. La escala puede ser mayor que la predeterminada para ayudar a los usuarios con menor capacidad de visión o menor para llenar la pantalla con más datos a la vez.

La fuente predeterminada de UIKit y SwiftUI incluye esta característica internamente, todo lo que el desarrollador tiene que hacer es configurar la fuente en la etiqueta con un estilo de fuente.
textLabel.font = .preferredFont(forTextStyle: .body)

Agregar fuente personalizada
Comience eligiendo una fuente para usar en el proyecto. Es recomendable utilizar una fuente con varios pesos para transmitir diferentes significados en la aplicación.
Las fuentes se pueden descargar desde una plataforma gratuita como Google Fonts .
Arrastre los archivos de fuentes al proyecto Xcode. La mejor práctica es crear una carpeta Font
y una subcarpeta para cada familia de fuentes.

Abra el objetivo principal Info.plist
y agregue la clave UIAppFonts
como una matriz. Dentro de la matriz, agregue el nombre de archivo y la extensión para cada una de las fuentes incluidas.

Los archivos de fuentes ahora se importan al proyecto y se pueden usar creando una instancia 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"]
La forma más fácil de usar una fuente personalizada en el proyecto Swift es asignar la fuente directamente a la etiqueta.
textLabel.font = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)
Ajuste del tamaño del texto en iOS
Configuración de accesibilidad
Inicie la aplicación Configuración en el dispositivo o en un simulador. Navegar a Accessibility > Display & Text Size > Larger Text
. El control deslizante cambiará el tamaño de fuente para el sistema.

Cambiar el tamaño del texto no hará que se inicie ninguna aplicación, pero se rehará el diseño.
⚙️ Esto es para iOS 15, otras versiones de iOS tendrán una ligera diferencia, pero la opción debería poder buscarse con Text Size
o Larger Text
.
Anulaciones del entorno de Xcode
En Xcode, después de ejecutar con éxito la aplicación en un simulador, busque el archivo Debug Area
. El Debug Area
contiene un botón con el símbolo de alterna. Este botón debería abrir el Environment Overrides
menú del simulador. El tamaño del texto se puede ajustar con el control deslizante para Dynamic Type
.

Environment Overrides
anulará la configuración del simulador y devolverá la configuración más reciente en el simulador cuando se apague.
Reiniciar la aplicación con la configuración del dispositivo cambiada debería mostrar el nuevo texto en la nueva escala. Sin embargo, no es posible cambiar el tamaño de fuente cuando la aplicación se está ejecutando. Lo que falta es una herramienta de escalado. Modifique el código para configurar el texto de la etiqueta de la siguiente manera:
let customFont = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)!
label.font = UIFontMetrics.default.scaledFont(for: customFont)
label.adjustsFontForContentSizeCategory = true
Para aprovechar UIFontMetrics
la capacidad, presentamos un ayudante:
func customFont(
_ font: DynamicFont,
forTextStyle style: UIFont.TextStyle,
overrideFontSize: UIContentSizeCategory? = nil
) -> UIFont?
Además de agregar otra capa a UIFontMetrics
, el asistente sirve como puerta de entrada para las funcionalidades que puede realizar la aplicación. La lista de requisitos incluye:
- Todas las fuentes personalizadas se pueden utilizar dentro de una función.
- Los tamaños de texto se distinguen por su estilo de texto (es decir, cuerpo, título, subtítulo, etc.).
- El tamaño del texto se puede anular con la configuración de la aplicación.
Primero, creamos un protocolo para elegir una fuente: DynamicFont
.
protocol DynamicFont {
func fontName() -> String
func fontSize(style: UIFont.TextStyle) -> CGFloat
}
El ejemplo de DynamicFont
nuestra demostración es el siguiente.
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 versión anterior del asistente se puede usar de inmediato en iOS 11. UILabel
Debería haberse adjustsFontForContentSizeCategory
configurado true
para permitir actualizaciones automáticas cuando el sistema cambia el tamaño del texto.
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.scaledFont
solo está disponible en iOS 11 y versiones posteriores. Para iOS 10, la escala de fuente deberá proporcionarse manualmente para cada estilo de texto y categoría de tamaño, además de actualizar la fuente cuando cambie el tamaño del texto del sistema.
Escala de fuente
Introducir un nuevo protocolo:
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
}
customFont
Será necesario modificar la función para adaptarse a las escalas de 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
}
Actualizar automáticamente el tamaño del texto
Actualmente, la aplicación mostrará la fuente correcta solo cuando se cargue por primera vez. La página deberá establecer la fuente para cada componente cada vez que cambie el tamaño del texto. Esto se puede hacer escuchando la NotificationCenter
notificación 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)
}
}
Para una no RxSwift
, no olvides llamar NotificationCenter.removeObserver
al deinit
.
El tamaño de fuente se actualizará automáticamente a medida que cambie el tamaño del texto del sistema.
SwiftUI
SwiftUI tiene un modificador de vista específicamente para modificar la fuente.
.font(.custom(name, size: size))
Text("Hello").font(.custom("ZenOldMincho-Regular", size: 16.0))
Actualización del tamaño de fuente
Para permitir la actualización del tamaño de fuente, se utilizará un nuevo modificador de vista para tener en cuenta el cambio en el tamaño del texto del sistema.
Si el proyecto es puramente SwiftUI, la declaración existente de customFont(_ font: DynamicFont, forTextStyle style: UIFont.TextStyle, overrideFontSize: UIContentSizeCategory? = nil) -> UIFont?
puede ignorarse.
La declaración de un método SwiftUI equivalente es:
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 declaración de ScaledFont
es:
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))
}
}
Con el modificador scaledFont
podemos cambiar la fuente en cualquier vista con una firma similar. La vista resultante actualizará el tamaño de fuente a medida que cambie la configuración del sistema.
Text("Hello")
.scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline)
La implementación actual de ScaledFont: ViewModifier
no incluye la anulación del tamaño de fuente dentro de la aplicación.
Para permitir la anulación, UIFontMetrics.scaledValue(for:, compatibleWith:)
se utilizará. Esto es lo mismo en UIKit
la implementación; sin embargo, la conversión de ContentSizeCategory
a UIContentSizeCategory
, para satisfacer scaledValue
la entrada de , solo es posible para iOS 14 y superior.
Modifique el código para ScaledFont.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))
}
Usando el modificador scaledFont
, ahora podemos anular el tamaño del texto.
Text("Hello")
.scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline, overrideFontSize: .extraLarge)
Swift está en constante evolución para permitir una fácil implementación de la accesibilidad para mejorar la calidad de vida del usuario. Las funciones auxiliares presentadas en este blog se pueden integrar convenientemente en proyectos nuevos y existentes.
Dynamic Font permitirá a los usuarios avanzados ver más datos de un vistazo y ayudará a los usuarios con problemas de visión a usar la aplicación sin problemas. La fuente dinámica es una de las muchas funciones de accesibilidad que los desarrolladores pueden adoptar para mejorar sus aplicaciones.
El código fuente de este proyecto está disponible en nuestro repositorio .
Referencias
Escalar fuentes personalizadas automáticamente con Dynamic Type Cómo usar Dynamic Type con una fuente personalizada Práctica Dynamic Type
Publicado originalmente en https://nimblehq.co .