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

设置UIBackgroundConfiguration的backgroundColor破坏默认颜色转换器问题

iOS 14+ UICollectionView列表单元格自定义背景色后丢失默认选中状态问题

在iOS 14及以上版本的UIKit中,我基于列表布局和Diffable DataSource创建了单分区单行的UICollectionView,核心实现代码如下:

class ViewController: UIViewController {
    var collectionView: UICollectionView!
    var dataSource: UICollectionViewDiffableDataSource<String, String>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureHierarchy()
        configureDataSource()
    }
    
    func configureHierarchy() {
        collectionView = .init(frame: .zero, collectionViewLayout: createLayout())
        view.addSubview(collectionView)
        collectionView.frame = view.bounds
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    }
    
    func createLayout() -> UICollectionViewLayout {
        UICollectionViewCompositionalLayout { section, layoutEnvironment in
            let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
            return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
        }
    }
    
    func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            var backgroundConfiguration = UIBackgroundConfiguration.listGroupedCell()
            backgroundConfiguration.backgroundColor = .systemBlue
            cell.backgroundConfiguration = backgroundConfiguration
        }
        
        dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
        }
        
        var snapshot = NSDiffableDataSourceSnapshot<String, String>()
        snapshot.appendSections(["main"])
        snapshot.appendItems(["demo"])
        dataSource.apply(snapshot, animatingDifferences: false)
    }
}

设置UIBackgroundConfiguration的backgroundColor为.systemBlue后,点击单元格无法显示默认选中状态——直接设置颜色会破坏单元格默认的UIConfigurationColorTransformer。我的需求是:保持自定义背景色,同时让单元格选中表现与未设置该属性时完全一致,且必须采用iOS 14推荐的Configuration方式配置外观。

尝试过的无效方法

  • 设置CollectionView代理允许选中行
  • 将颜色转换器设为.grayscale
  • 为backgroundConfiguration应用updated(for:)方法
  • 引用默认配置的颜色转换器
  • 使用CollectionViewController并禁用自动清除选中
  • 切换automaticallyUpdatesBackgroundConfiguration属性
  • 将配置代码放入configurationUpdateHandler
  • 组合上述多种方法
  • 引用列表单元格配置的颜色转换器(均为nil)

临时可行解决方案

目前有两种可实现需求的临时方案,但都不符合理想预期:

方案1:自定义颜色转换器

根据单元格状态返回对应颜色:

var backgroundConfiguration = UIBackgroundConfiguration.listGroupedCell()
backgroundConfiguration.backgroundColorTransformer = .init { _ in
    if cell.configurationState.isSelected || cell.configurationState.isHighlighted || cell.configurationState.isFocused {
        .systemRed
    } else {
        .systemBlue
    }
}
cell.backgroundConfiguration = backgroundConfiguration

方案2:改用backgroundView和selectedBackgroundView

放弃使用BackgroundConfiguration,直接设置背景视图:

let v = UIView()
v.backgroundColor = .systemBlue
cell.selectedBackgroundView = v

或完整配置内容与背景视图:

var contentConfiguration = UIListContentConfiguration.cell()
contentConfiguration.text = "Hello"
cell.contentConfiguration = contentConfiguration

let v = UIView()
v.backgroundColor = .systemBlue
cell.backgroundView = v

let bv = UIView()
bv.backgroundColor = .systemRed
cell.selectedBackgroundView = bv

两种方案均兼容视图出现时取消选中的逻辑:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    deselectSelectedItems(animated: animated)
}

func deselectSelectedItems(animated: Bool) {
    if let indexPath = collectionView.indexPathsForSelectedItems?.first {
        if let coordinator = transitionCoordinator {
            coordinator.animate(alongsideTransition: { [weak self] context in
                self?.collectionView.deselectItem(at: indexPath, animated: true)
            }) { [weak self] (context) in
                if context.isCancelled {
                    self?.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])
                }
            }
        } else {
            collectionView.deselectItem(at: indexPath, animated: animated)
        }
    }
}

寻求理想解决方案

希望找到无需自定义颜色转换器、也无需放弃Configuration的方案——即通过恢复默认设置,在保留自定义背景色的同时,让单元格拥有原生的选中状态表现。

内容的提问来源于stack exchange,提问作者Filippo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:10:07