// // FontManager.swift // QuickLocation // // Created by 八条 on 2026/8/5. // import UIKit /// 项目自定义字体样式 enum AppFont { /// 荆南波波黑-Bold case boboBold /// 字魂扁黑体 case ziHunBianHei /// 优设标题黑 case youSheBiaoTiHei /// 候选字体名(按优先级;部分字体 PostScript 名异常,需多试) var candidateNames: [String] { switch self { case .boboBold: // TTF Full Name 为「荆南波波黑 Bold」,PostScript 名为异常的「-Bold」 return ["荆南波波黑 Bold", "荆南波波黑-Bold", "JingNanBoBoHei-Bold"] case .ziHunBianHei: return ["zihunbiantaoti", "字魂扁黑体"] case .youSheBiaoTiHei: // PostScript / Full Name 均为 YouSheBiaoTiHei return ["YouSheBiaoTiHei", "优设标题黑"] } } var familyName: String? { switch self { case .boboBold: return "荆南波波黑" case .ziHunBianHei: return nil case .youSheBiaoTiHei: return "YouSheBiaoTiHei" } } var fileName: String { switch self { case .boboBold: return "荆南波波黑-Bold.ttf" case .ziHunBianHei: return "zihunbiantaoti-r.ttf" case .youSheBiaoTiHei: return "优设标题黑_猫啃网.ttf" } } var fallbackWeight: UIFont.Weight { switch self { case .boboBold: return .bold case .ziHunBianHei: return .medium case .youSheBiaoTiHei: return .bold } } } /// 统一字体管理:取字体 + 启动注册 enum FontManager { private static var resolvedNames: [AppFont: String] = [:] private static var didRegister = false /// 按样式与字号取字体,失败回退系统字体 static func font(_ style: AppFont, size: CGFloat) -> UIFont { ensureRegistered() if let name = resolvedFontName(for: style), let custom = UIFont(name: name, size: size) { return custom } return .systemFont(ofSize: size, weight: style.fallbackWeight) } static func boboBold(_ size: CGFloat) -> UIFont { font(.boboBold, size: size) } static func ziHunBianHei(_ size: CGFloat) -> UIFont { font(.ziHunBianHei, size: size) } static func youSheBiaoTiHei(_ size: CGFloat) -> UIFont { font(.youSheBiaoTiHei, size: size) } /// 注册 Bundle 内自定义字体(可重复调用) static func registerCustomFonts() { for style in [AppFont.boboBold, .ziHunBianHei, .youSheBiaoTiHei] { if let registered = UIFont.loadFontName(style.fileName), !registered.isEmpty { // 忽略异常 PostScript(如 "-Bold"),优先用可实例化的名 if !registered.hasPrefix("-"), UIFont(name: registered, size: 12) != nil { resolvedNames[style] = registered continue } } if let name = resolveAvailableName(for: style) { resolvedNames[style] = name } } didRegister = true } private static func ensureRegistered() { guard !didRegister else { return } registerCustomFonts() } private static func resolvedFontName(for style: AppFont) -> String? { if let cached = resolvedNames[style] { return cached } if let name = resolveAvailableName(for: style) { resolvedNames[style] = name return name } return nil } private static func resolveAvailableName(for style: AppFont) -> String? { for name in style.candidateNames { if UIFont(name: name, size: 12) != nil { return name } } if let family = style.familyName { let names = UIFont.fontNames(forFamilyName: family) if let first = names.first { return first } } return nil } }