60 lines
2.1 KiB
Swift
60 lines
2.1 KiB
Swift
//
|
||
// HomeMenuIconFactory.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import UIKit
|
||
|
||
/// 首页 / 全部功能菜单图标加载,统一 SF Symbol 与资源图的视觉尺寸。
|
||
enum HomeMenuIconFactory {
|
||
|
||
/// 菜单图标统一使用的逻辑画布尺寸。
|
||
static let canvasSize = CGSize(width: 24, height: 24)
|
||
|
||
/// 与菜单图标槽位(约 24–26pt)对齐的系统图标配置。
|
||
static let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 18, weight: .medium)
|
||
|
||
private static let imageCache = NSCache<NSString, UIImage>()
|
||
|
||
/// 优先加载 Assets 资源图并归一化画布;SF Symbol 保留系统符号表示与分层渲染。
|
||
static func image(named iconName: String) -> UIImage? {
|
||
let cacheKey = iconName as NSString
|
||
if let cachedImage = imageCache.object(forKey: cacheKey) {
|
||
return cachedImage
|
||
}
|
||
|
||
let image: UIImage?
|
||
if let assetImage = UIImage(named: iconName) {
|
||
image = renderOnFixedCanvas(assetImage)
|
||
} else {
|
||
image = UIImage(systemName: iconName, withConfiguration: symbolConfiguration)
|
||
}
|
||
|
||
if let image {
|
||
imageCache.setObject(image, forKey: cacheKey)
|
||
}
|
||
return image
|
||
}
|
||
|
||
private static func renderOnFixedCanvas(_ image: UIImage) -> UIImage {
|
||
let sourceSize = image.size
|
||
guard sourceSize.width > 0, sourceSize.height > 0 else {
|
||
return image
|
||
}
|
||
|
||
let scale = min(canvasSize.width / sourceSize.width, canvasSize.height / sourceSize.height)
|
||
let drawSize = CGSize(width: sourceSize.width * scale, height: sourceSize.height * scale)
|
||
let drawRect = CGRect(
|
||
x: (canvasSize.width - drawSize.width) / 2,
|
||
y: (canvasSize.height - drawSize.height) / 2,
|
||
width: drawSize.width,
|
||
height: drawSize.height
|
||
)
|
||
let renderer = UIGraphicsImageRenderer(size: canvasSize)
|
||
let renderedImage = renderer.image { _ in
|
||
image.withRenderingMode(.alwaysOriginal).draw(in: drawRect)
|
||
}
|
||
return renderedImage.withRenderingMode(.alwaysTemplate)
|
||
}
|
||
}
|