You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIKit中UITableView重载后SF Symbols尺寸异常波动求助

嵌套UICollectionView的UITableView重载后SF Symbols尺寸异常波动

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

SF Symbols尺寸波动演示

相关代码

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布局截图

UIViewController布局截图

解决方法

这个问题主要是由于符号尺寸未固定、频繁重建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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:43:21