UIKit中UITableView重载后SF Symbols尺寸异常波动求助
嵌套UICollectionView的UITableView重载后SF Symbols尺寸异常波动
在UIKit应用中,界面包含嵌套UICollectionView的UITableView,UITableView每隔几秒会重载,每次重载后,UICollectionView单元格内的SF Symbols尺寸都会轻微变化(演示时将重载定时器设为1秒)。

相关代码
ViewController 代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { ... productsCollectionView.reloadData() return cell } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "verbindungCollectionViewCell", for: indexPath) as! verbindungCollectionViewCell if legArray[tempIndexPathFromTableView.row][0][indexPath.row] is PublicLeg { //Public Leg var tempPublicLeg = legArray[tempIndexPathFromTableView.row][0][indexPath.row] as! PublicLeg cell.serviceLabel.text = tempPublicLeg.line.label cell.serviceImageView.image = getProductSymbol(productType: productToTransportType(product: tempPublicLeg.line.product!), designPack: .automatic) cell.setCancelled(tempPublicLeg.isCancelled) if tempPublicLeg.isCancelled == true { } } else { //Individual Leg (Walk) var tempIndLeg = legArray[tempIndexPathFromTableView.row][0][indexPath.row] as! IndividualLeg cell.serviceImageView.image = getProductSymbol(productType: .walk, designPack: .automatic) cell.serviceLabel.text = tempIndLeg.departure.getDistanceText(CLLocation(latitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lat ?? 0)/1000000, longitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lon ?? 0)/1000000)) } return cell }
生成SF Symbols的函数
func getProductSymbol(productType: TransportType, designPack: DesignPack) -> UIImage? { ...Determinate color, symbol etc... if colorType == .singleColor { let config = UIImage.SymbolConfiguration(hierarchicalColor: colors[0]) let image = UIImage(systemName: symbolName, withConfiguration: config)?.withRenderingMode(.automatic) return image } else if colorType == .multipleColor { let config = UIImage.SymbolConfiguration(paletteColors: colors) let image = UIImage(systemName: symbolName, withConfiguration: config)?.withRenderingMode(.automatic) return image } else { return nil } }
Storyboard布局截图

解决方法
这个问题主要是由于符号尺寸未固定、频繁重建Symbol以及不合理的重载逻辑共同导致的,可按以下步骤修复:
固定SF Symbol的尺寸配置
在生成Symbol时明确指定大小,避免系统自动调整。修改getProductSymbol函数,添加固定尺寸的配置:func getProductSymbol(productType: TransportType, designPack: DesignPack) -> UIImage? { // ... 原有逻辑:确定color、symbolName等 ... // 先创建固定尺寸配置,根据需求调整大小和权重 let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .regular) var finalConfig = sizeConfig if colorType == .singleColor { finalConfig = finalConfig.applying(UIImage.SymbolConfiguration(hierarchicalColor: colors[0])) let image = UIImage(systemName: symbolName, withConfiguration: finalConfig)?.withRenderingMode(.automatic) return image } else if colorType == .multipleColor { finalConfig = finalConfig.applying(UIImage.SymbolConfiguration(paletteColors: colors)) let image = UIImage(systemName: symbolName, withConfiguration: finalConfig)?.withRenderingMode(.automatic) return image } else { return nil } }固定ImageView的约束与显示模式
在Storyboard中给serviceImageView设置固定宽高约束,同时将contentMode设为.scaleAspectFit,避免单元格复用过程中图片被拉伸或压缩。优化重载逻辑
不要在tableView(_:cellForRowAt:)中调用productsCollectionView.reloadData(),这种写法会导致TableView每复用一个单元格就强制刷新一次CollectionView,加剧布局波动。建议:- 仅当数据源确实变化时,才刷新对应位置的CollectionView;
- 将CollectionView的数据源更新逻辑移到单元格的
awakeFromNib()或prepareForReuse()方法中。
缓存生成的SF Symbol
对已生成的Symbol进行缓存,避免每次重载都重复创建。可以用字典做缓存容器:private var symbolCache: [String: UIImage] = [:] func getProductSymbol(productType: TransportType, designPack: DesignPack) -> UIImage? { let cacheKey = "\(productType.rawValue)-\(designPack.rawValue)" if let cachedImage = symbolCache[cacheKey] { return cachedImage } // ... 原有生成逻辑 ... if let image = image { symbolCache[cacheKey] = image } return image }
内容的提问来源于stack exchange,提问作者Victor Lobe
相关产品推荐
相关产品推荐

