Adicionando digitação personalizada dinâmica ao seu projeto iOS — Nimble

Introdução
Dynamic Type
é um recurso de acessibilidade no iOS e macOS. O recurso permite que o usuário defina uma escala de texto que é aplicada a todo o dispositivo, atualizada automaticamente. A escala pode ser maior do que o padrão para ajudar usuários com baixa capacidade de visão ou menor para preencher a tela com mais dados de uma só vez.

A fonte padrão do UIKit e SwiftUI inclui esse recurso internamente, tudo o que o desenvolvedor precisa fazer é definir a fonte no rótulo com um estilo de fonte.
textLabel.font = .preferredFont(forTextStyle: .body)

Adicionando fonte personalizada
Comece escolhendo uma fonte para usar no projeto. É aconselhável usar uma fonte com vários pesos para transmitir diferentes significados no aplicativo.
As fontes podem ser baixadas de uma plataforma gratuita, como o Google Fonts .
Arraste os arquivos de fonte para o projeto Xcode. A melhor prática é criar uma pasta Font
e uma subpasta para cada família de fontes.

Abra o alvo principal Info.plist
e adicione a chave UIAppFonts
como uma matriz. Dentro da matriz, adicione o nome do arquivo e a extensão de cada uma das fontes incluídas.

Os arquivos de fonte agora são importados para o projeto e podem ser usados criando uma instância 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"]
A maneira mais fácil de usar uma fonte personalizada no projeto Swift é atribuir a fonte diretamente ao rótulo.
textLabel.font = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)
Ajustando o tamanho do texto no iOS
Configurações de acessibilidade
Inicie o aplicativo Configurações no dispositivo ou em um simulador. Navegue até Accessibility > Display & Text Size > Larger Text
. O controle deslizante alterará o tamanho da fonte do sistema.

Alterar o tamanho do texto não iniciará nenhum aplicativo, mas o layout será refeito.
⚙️ Isso é para iOS 15, outras versões do iOS terão uma pequena diferença, mas a opção deve ser pesquisada com Text Size
ou Larger Text
.
Substituições do ambiente Xcode
No Xcode, depois de executar com sucesso o aplicativo em um simulador, localize o arquivo Debug Area
. O Debug Area
contém um botão com o símbolo de alternância. Este botão deve abrir o Environment Overrides
menu do simulador. O tamanho do texto pode ser ajustado com o controle deslizante para Dynamic Type
.

Environment Overrides
substituirá as configurações do simulador e retornará as configurações mais recentes no simulador quando desligado.
Reiniciar o aplicativo com a configuração do dispositivo alterada deve mostrar o novo texto na nova escala. No entanto, não é possível alterar o tamanho da fonte durante a execução do aplicativo. O que falta é uma ferramenta de dimensionamento. Modifique o código para definir o texto do rótulo da seguinte forma:
let customFont = UIFont(name: "ZenOldMincho-Regular", size: UIFont.labelFontSize)!
label.font = UIFontMetrics.default.scaledFont(for: customFont)
label.adjustsFontForContentSizeCategory = true
Para alavancar UIFontMetrics
a capacidade, apresentamos um auxiliar:
func customFont(
_ font: DynamicFont,
forTextStyle style: UIFont.TextStyle,
overrideFontSize: UIContentSizeCategory? = nil
) -> UIFont?
Além de adicionar outra camada ao UIFontMetrics
, o helper serve como gateway para as funcionalidades que o aplicativo pode fazer. A lista de requisitos inclui:
- Todas as fontes personalizadas podem ser usadas em uma função.
- Os tamanhos de texto são distinguíveis por seu estilo de texto (ou seja: corpo, título, legenda, etc.).
- O tamanho do texto pode ser substituído pelas configurações do aplicativo.
Primeiramente, criamos um protocolo para escolha da fonte: DynamicFont
.
protocol DynamicFont {
func fontName() -> String
func fontSize(style: UIFont.TextStyle) -> CGFloat
}
O exemplo de DynamicFont
nossa demonstração é o seguinte.
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)
A versão acima do helper pode ser usada imediatamente no iOS 11. UILabel
Deve ter adjustsFontForContentSizeCategory
configurado true
para permitir atualizações automáticas quando o sistema altera o tamanho do 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
está disponível apenas no iOS 11 e posterior. Para iOS 10, a escala da fonte precisará ser fornecida manualmente para cada estilo de texto e categoria de tamanho, bem como atualizar a fonte quando o tamanho do texto do sistema mudar.
Escala de fonte
Introduzir um novo 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
}
A função customFont
precisará ser modificada para acomodar as escalas do 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
}
Atualizar automaticamente o tamanho do texto
Atualmente, o aplicativo mostrará a fonte correta somente quando for carregado pela primeira vez. A página precisará definir a fonte para cada componente sempre que o tamanho do texto for alterado. Isso pode ser feito ouvindo a NotificationCenter
notificação do 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 quem não RxSwift
, não esqueça de ligar NotificationCenter.removeObserver
no deinit
.
O tamanho da fonte será atualizado automaticamente à medida que o tamanho do texto do sistema for alterado.
SwiftUI
SwiftUI tem um modificador de visualização especificamente para modificar a fonte.
.font(.custom(name, size: size))
Text("Hello").font(.custom("ZenOldMincho-Regular", size: 16.0))
Atualizando tamanho da fonte
Para permitir a atualização do tamanho da fonte, um novo modificador de visualização será usado para dar conta da mudança no tamanho do texto do sistema.
Se o projeto for puramente SwiftUI, a declaração existente de customFont(_ font: DynamicFont, forTextStyle style: UIFont.TextStyle, overrideFontSize: UIContentSizeCategory? = nil) -> UIFont?
pode ser ignorada.
A declaração de um método SwiftUI equivalente é:
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
)
)
}
}
A declaração de ScaledFont
é:
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))
}
}
Com o modificador, scaledFont
podemos alterar a fonte em qualquer exibição com uma assinatura semelhante. A exibição resultante atualizará o tamanho da fonte à medida que as configurações do sistema forem alteradas.
Text("Hello")
.scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline)
A implementação atual de ScaledFont: ViewModifier
não inclui a substituição do tamanho da fonte no aplicativo.
Para permitir a substituição, UIFontMetrics.scaledValue(for:, compatibleWith:)
será usado. Isso é o mesmo na UIKit
implementação; no entanto, a conversão de ContentSizeCategory
para UIContentSizeCategory
, para satisfazer scaledValue
a entrada de, só é possível para iOS 14 e superior.
Modifique o 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 o modificador scaledFont
, agora podemos substituir o tamanho do texto.
Text("Hello")
.scaledFont(font: ZenOldMincho.bold, forTextStyle: .headline, overrideFontSize: .extraLarge)
Swift está em constante evolução para permitir fácil implementação de acessibilidade para melhorar a qualidade de vida do usuário. As funções auxiliares apresentadas neste blog podem ser convenientemente integradas em projetos novos e existentes.
A fonte dinâmica permitirá que os usuários avançados vejam mais dados rapidamente, além de ajudar os usuários com problemas de visão a usar o aplicativo sem problemas. Fonte dinâmica é um dos muitos recursos de acessibilidade que os desenvolvedores podem adotar para melhorar seus aplicativos.
O código-fonte deste projeto está disponível em nosso repositório .
Referências
Dimensionando fontes personalizadas automaticamente com o Dynamic Type Como usar o Dynamic Type com uma fonte personalizada Prático Dynamic Type
Originalmente publicado em https://nimblehq.co .