-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSTFontManager.swift
More file actions
202 lines (182 loc) · 8.18 KB
/
STFontManager.swift
File metadata and controls
202 lines (182 loc) · 8.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//
// STFontManager.swift
// STBaseProject
//
// Created by 寒江孤影 on 2018/10/10.
//
import UIKit
public struct STFontFamilyConfig: Sendable, Equatable {
public var regular: String?
public var medium: String?
public var semibold: String?
public var bold: String?
public var light: String?
public var ultraLight: String?
public var thin: String?
public var heavy: String?
public var black: String?
/// 使用系统默认字体(简体中文环境下系统会自动选用苹方)
public static let system = STFontFamilyConfig()
public init(
regular: String? = nil,
medium: String? = nil,
semibold: String? = nil,
bold: String? = nil,
light: String? = nil,
ultraLight: String? = nil,
thin: String? = nil,
heavy: String? = nil,
black: String? = nil
) {
self.regular = regular
self.medium = medium
self.semibold = semibold
self.bold = bold
self.light = light
self.ultraLight = ultraLight
self.thin = thin
self.heavy = heavy
self.black = black
}
func fontName(for weight: UIFont.Weight) -> String? {
switch weight {
case .regular: return regular
case .medium: return medium
case .semibold: return semibold
case .bold: return bold
case .light: return light
case .ultraLight: return ultraLight
case .thin: return thin
case .heavy: return heavy
case .black: return black
default: return nil
}
}
}
// MARK: - STFontManager
public final class STFontManager {
public static let shared = STFontManager()
private let configurationLock = NSLock()
private var storedFontFamily: STFontFamilyConfig = .system
public var fontFamily: STFontFamilyConfig {
self.configurationLock.lock()
defer { self.configurationLock.unlock() }
return self.storedFontFamily
}
private init() {}
public func configure(fontFamily: STFontFamilyConfig) {
self.configurationLock.lock()
defer { self.configurationLock.unlock() }
self.storedFontFamily = fontFamily
}
public func reset() {
self.configurationLock.lock()
defer { self.configurationLock.unlock() }
self.storedFontFamily = .system
}
}
// MARK: - UIFontMetrics 方案(支持 Dynamic Type)
public extension UIFont {
/// 使用自定义字体族 + UIFontMetrics 缩放,支持 Dynamic Type
/// 迁移时只需: UIFont.preferredFont(forTextStyle: .body) → UIFont.st_preferredFont(ofSize: 14, forTextStyle: .body)
/// - Parameters:
/// - size: 基准字号(设计稿尺寸)
/// - style: 文本样式,用于 UIFontMetrics 缩放(默认 .body)
/// - weight: 字重(默认 .regular)
/// - maxSize: 最大字号限制(可选)
static func st_preferredFont(ofSize size: CGFloat, forTextStyle style: UIFont.TextStyle = .body, weight: UIFont.Weight = .regular, maxSize: CGFloat? = nil) -> UIFont {
let config = STFontManager.shared.fontFamily
let baseFont: UIFont
if let name = config.fontName(for: weight),
let customFont = UIFont(name: name, size: size) {
baseFont = customFont
} else {
baseFont = UIFont.systemFont(ofSize: size, weight: weight)
}
let metrics = UIFontMetrics(forTextStyle: style)
if let maxSize = maxSize {
return metrics.scaledFont(for: baseFont, maximumPointSize: maxSize)
}
return metrics.scaledFont(for: baseFont)
}
/// 使用指定字体名 + UIFontMetrics 缩放,支持 Dynamic Type
/// - Parameters:
/// - name: 字体名称
/// - size: 基准字号
/// - style: 文本样式,用于 UIFontMetrics 缩放(默认 .body)
/// - maxSize: 最大字号限制(可选)
static func st_preferredFont(name: String, ofSize size: CGFloat, forTextStyle style: UIFont.TextStyle = .body, maxSize: CGFloat? = nil) -> UIFont {
let baseFont = UIFont(name: name, size: size) ?? .systemFont(ofSize: size)
let metrics = UIFontMetrics(forTextStyle: style)
if let maxSize = maxSize {
return metrics.scaledFont(for: baseFont, maximumPointSize: maxSize)
}
return metrics.scaledFont(for: baseFont)
}
}
// MARK: - 便捷方法(与 UIFont.systemFont 签名一致,方便替换)
public extension UIFont {
/// 替换 UIFont.systemFont(ofSize:)
/// 使用自定义字体族 + 屏幕适配缩放
/// 迁移时只需: UIFont.systemFont(ofSize: 14) → UIFont.st_systemFont(ofSize: 14)
static func st_systemFont(ofSize size: CGFloat) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
let config = STFontManager.shared.fontFamily
if let name = config.fontName(for: .regular),
let font = UIFont(name: name, size: scaledSize) {
return font
}
return .systemFont(ofSize: scaledSize)
}
/// 替换 UIFont.systemFont(ofSize:weight:)
/// 迁移时只需: UIFont.systemFont(ofSize: 14, weight: .medium) → UIFont.st_systemFont(ofSize: 14, weight: .medium)
static func st_systemFont(ofSize size: CGFloat, weight: UIFont.Weight) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
let config = STFontManager.shared.fontFamily
if let name = config.fontName(for: weight),
let font = UIFont(name: name, size: scaledSize) {
return font
}
return UIFont.systemFont(ofSize: scaledSize, weight: weight)
}
/// 替换 UIFont.boldSystemFont(ofSize:)
/// 迁移时只需: UIFont.boldSystemFont(ofSize: 14) → UIFont.st_boldSystemFont(ofSize: 14)
static func st_boldSystemFont(ofSize size: CGFloat) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
let config = STFontManager.shared.fontFamily
if let name = config.fontName(for: .semibold),
let font = UIFont(name: name, size: scaledSize) {
return font
}
return UIFont.boldSystemFont(ofSize: scaledSize)
}
/// 替换 UIFont.italicSystemFont(ofSize:)
/// 迁移时只需: UIFont.italicSystemFont(ofSize: 14) → UIFont.st_italicSystemFont(ofSize: 14)
static func st_italicSystemFont(ofSize size: CGFloat) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
return UIFont.italicSystemFont(ofSize: scaledSize)
}
/// 替换 UIFont.preferredFont(forTextStyle:)
/// 使用自定义字体族 + UIFontMetrics 缩放,支持 Dynamic Type
/// 字号由系统 TextStyle 自动决定,无需手动传入
/// 迁移时只需: UIFont.preferredFont(forTextStyle: .body) → UIFont.st_preferredFont(forTextStyle: .body)
static func st_preferredFont(forTextStyle style: UIFont.TextStyle, weight: UIFont.Weight = .regular) -> UIFont {
let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: style)
let pointSize = descriptor.pointSize
return st_preferredFont(ofSize: pointSize, forTextStyle: style, weight: weight)
}
/// 替换 UIFont.monospacedDigitSystemFont(ofSize:weight:)
/// 等宽数字字体,适用于计时器、价格等需要数字对齐的场景
/// 迁移时只需: UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .regular) → UIFont.st_monospacedDigitSystemFont(ofSize: 14, weight: .regular)
static func st_monospacedDigitSystemFont(ofSize size: CGFloat, weight: UIFont.Weight) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
return .monospacedDigitSystemFont(ofSize: scaledSize, weight: weight)
}
/// 替换 UIFont.monospacedSystemFont(ofSize:weight:)
/// 等宽字体,适用于代码块、终端等需要等宽排列的场景
/// 迁移时只需: UIFont.monospacedSystemFont(ofSize: 14, weight: .regular) → UIFont.st_monospacedSystemFont(ofSize: 14, weight: .regular)
static func st_monospacedSystemFont(ofSize size: CGFloat, weight: UIFont.Weight) -> UIFont {
let scaledSize = STDeviceAdapter.scaledWidth(size)
return .monospacedSystemFont(ofSize: scaledSize, weight: weight)
}
}