diff --git a/suixinkan/Features/Home/Services/HomeMenuIconFactory.swift b/suixinkan/Features/Home/Services/HomeMenuIconFactory.swift index 3edf06a..8369e21 100644 --- a/suixinkan/Features/Home/Services/HomeMenuIconFactory.swift +++ b/suixinkan/Features/Home/Services/HomeMenuIconFactory.swift @@ -16,21 +16,24 @@ enum HomeMenuIconFactory { private static let imageCache = NSCache() - /// 优先加载 Assets 资源图;否则加载 SF Symbol,并统一渲染到固定画布。 + /// 优先加载 Assets 资源图并归一化画布;SF Symbol 保留系统符号表示与分层渲染。 static func image(named iconName: String) -> UIImage? { let cacheKey = iconName as NSString if let cachedImage = imageCache.object(forKey: cacheKey) { return cachedImage } - guard let sourceImage = UIImage(named: iconName) - ?? UIImage(systemName: iconName, withConfiguration: symbolConfiguration) else { - return nil + let image: UIImage? + if let assetImage = UIImage(named: iconName) { + image = renderOnFixedCanvas(assetImage) + } else { + image = UIImage(systemName: iconName, withConfiguration: symbolConfiguration) } - let normalizedImage = renderOnFixedCanvas(sourceImage) - imageCache.setObject(normalizedImage, forKey: cacheKey) - return normalizedImage + if let image { + imageCache.setObject(image, forKey: cacheKey) + } + return image } private static func renderOnFixedCanvas(_ image: UIImage) -> UIImage { diff --git a/suixinkanTests/HomeMenuIconFactoryTests.swift b/suixinkanTests/HomeMenuIconFactoryTests.swift index 0148110..c1044eb 100644 --- a/suixinkanTests/HomeMenuIconFactoryTests.swift +++ b/suixinkanTests/HomeMenuIconFactoryTests.swift @@ -18,20 +18,20 @@ final class HomeMenuIconFactoryTests: XCTestCase { XCTAssertNil(UIImage(systemName: "home_menu_space")) } - func testSystemSymbolsUseFixedCanvas() { + func testSystemSymbolsPreserveSymbolRepresentation() { let iconNames = [ "ellipsis", "dot.radiowaves.left.and.right", "rectangle.stack.badge.plus", + "mappin.circle.fill", ] for iconName in iconNames { let image = HomeMenuIconFactory.image(named: iconName) XCTAssertNotNil(image) - XCTAssertEqual(image?.size, HomeMenuIconFactory.canvasSize) - XCTAssertEqual(image?.renderingMode, .alwaysTemplate) - XCTAssertFalse(image?.isSymbolImage ?? true) + XCTAssertTrue(image?.isSymbolImage ?? false) + XCTAssertNotNil(image?.symbolConfiguration) } } @@ -39,6 +39,13 @@ final class HomeMenuIconFactoryTests: XCTestCase { XCTAssertNotNil(HomeMenuIconFactory.image(named: "dot.radiowaves.left.and.right")) XCTAssertNotNil(HomeMenuIconFactory.image(named: "rectangle.stack.badge.plus")) } + + func testLocationReportIconKeepsSystemSymbolLayers() { + let image = HomeMenuIconFactory.image(named: "mappin.circle.fill") + + XCTAssertNotNil(image) + XCTAssertTrue(image?.isSymbolImage ?? false) + } } /// 首页常用应用 cell 的图标布局与复用测试。 @@ -50,6 +57,7 @@ final class HomeMenuCellTests: XCTestCase { let menus = [ HomeMenuItem(uri: "space", title: "空间设置", iconName: "home_menu_space"), HomeMenuItem(uri: "live", title: "直播管理", iconName: "dot.radiowaves.left.and.right"), + HomeMenuItem(uri: "location", title: "位置上报", iconName: "mappin.circle.fill"), HomeMenuItem(uri: "more", title: "更多功能", iconName: "ellipsis"), ] @@ -60,11 +68,19 @@ final class HomeMenuCellTests: XCTestCase { cell.layoutIfNeeded() let iconView = try XCTUnwrap(findImageView(in: cell, identifier: menu.iconName)) - XCTAssertEqual(iconView.bounds.size, CGSize(width: 24, height: 24)) + let alignmentSize = iconView.alignmentRect(forFrame: iconView.frame).size + XCTAssertEqual(alignmentSize.width, 24, accuracy: 0.001) + XCTAssertEqual(alignmentSize.height, 24, accuracy: 0.001) XCTAssertEqual(iconView.superview?.bounds.size, CGSize(width: 40, height: 40)) - XCTAssertEqual(iconView.image?.size, HomeMenuIconFactory.canvasSize) XCTAssertEqual(iconView.contentMode, .center) XCTAssertNil(iconView.preferredSymbolConfiguration) + + if menu.iconName == "home_menu_space" { + XCTAssertEqual(iconView.image?.size, HomeMenuIconFactory.canvasSize) + XCTAssertFalse(iconView.image?.isSymbolImage ?? true) + } else { + XCTAssertTrue(iconView.image?.isSymbolImage ?? false) + } } }