如何根据设备主题更改 collectionview 单元格颜色(按照我的配色方案)

How to change collectionview cells color based on device theme (following my color scheme)

概览:

我正在使用集合视图构建键盘扩展。我希望单元格根据设备主题 (light/dark) 改变颜色。目前,当我为我的 collectionview 单元格设置配色方案时,它们不起作用。我用“///”注释标记了我的代码中有问题的部分。

资源:

我找到了 this RayWenderlich project,我喜欢他们处理颜色变化的方式,所以我复制了它。

我的代码:

我有3个类:

  1. 键盘视图控制器
  2. 包含键盘按钮的自定义视图
  3. 自定义集合视图单元格

CollectionView 单元格

class KeyboardKeys: UICollectionViewCell {
    
    var defaultColor = UIColor.white
    var highlighColor = UIColor.lightGray.withAlphaComponent(0.6)
    
    let label: UILabel = {
        let iv = UILabel()
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.contentMode =  .scaleAspectFit
        iv.font = UIFont.systemFont(ofSize: 20)
        iv.clipsToBounds = true
        iv.numberOfLines = 1
        iv.textAlignment = .center
        
        return iv
    }()

    override init(frame: CGRect) {
        super.init(frame: .zero)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    func commonInit() {
        contentView.addSubview(label)
        label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        label.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
        label.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true   
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
            backgroundColor = isHighlighted ? highlighColor : defaultColor  
    }   
}

自定义视图

class lettersKeyboard: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
var keyView: UICollectionView!
 let letters = ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]
 override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
        
    }
    
    private func commonInit(){
//If you find some errors it's because this is way different in my code. This is just a regulare  collection view anyway

    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .vertical
        
    keyView = UICollectionView(frame: CGRect(x: 0.0, y: 0.0 , width: frame.width, height: 280), collectionViewLayout: layout)
    keyView.setCollectionViewLayout(layout, animated: true)
    keyView.isScrollEnabled = false
    keyView.register(KeyboardKeys.self, forCellWithReuseIdentifier: "collectionCellId")
    keyView.delegate = self
    keyView.dataSource = self
    addSubview(keyView)
}

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        10
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = keyView.dequeueReusableCell(withReuseIdentifier: "collectionCellId", for: indexPath) as! KeyboardKeys
        cell.label.text = letters[indexPath.row]
        return cell
    }
    ///I guess something is wrong here 
    func setColorScheme(_ colorScheme: ColorScheme) {
      let colorScheme = CColors(colorScheme: colorScheme)
     
      for view in subviews {
        if let cell = view as? KeyboardKeys {
            cell.tintColor = colorScheme.buttonTextColor
            cell.defaultColor = colorScheme.keysDefaultColor
            cell.highlighColor = colorScheme.keysHighlightColor
      }
      }
    }
    
}

配色方案结构

enum ColorScheme {
    case dark
    case light
}

struct CColors {
    
    let keysDefaultColor: UIColor
    let keysHighlightColor: UIColor
    
    let buttonTextColor: UIColor
   
    
    init(colorScheme: ColorScheme) {
        switch colorScheme {
        case .light:
           
            keysDefaultColor = .systemRed
                //UIColor.white
            keysHighlightColor = UIColor.lightGray.withAlphaComponent(0.6)
         
            buttonTextColor = .black
           
        case .dark:
            
            keysDefaultColor = .systemBlue
                // UIColor.gray.withAlphaComponent(0.5)
            keysHighlightColor = UIColor.lightGray.withAlphaComponent(0.5)
            
            buttonTextColor = .white  
        }
    }
}

键盘视图控制器

class KeyboardViewController: UIInputViewController {
var letters : lettersKeyboard = {
      
        let m = lettersKeyboard(frame: .zero)
            m.translatesAutoresizingMaskIntoConstraints = false

            m.backgroundColor = .clear
            return m
        
}()
override func viewDidLoad() {
        super.viewDidLoad()
 
        view.addSubview(letters)
   
        letters.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        letters.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        letters.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        letters.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
//The rest is the default inputvc stuff 

    ///Or here
    override func textDidChange(_ textInput: UITextInput?) {
        // The app has just changed the document's contents, the document context has been updated.
       
        let colorScheme:  ColorScheme
        let proxy = self.textDocumentProxy
        if proxy.keyboardAppearance == UIKeyboardAppearance.dark {
            colorScheme = .dark
        } else {
            colorScheme = .light
        }
        letters.setColorScheme(colorScheme)
    }
}

问题:

我不知道我做错了什么,因为我的代码适用于除 collectionview 单元格之外的所有内容。我想存在另一种做这些事情的方法。那么如何根据我的配色方案根据设备的主题更改我的 collectionView 单元格的颜色?

你真的应该重新加载集合视图,而不是试图找到作为键的子视图,然后更新它们。

将 colorScheme 模型传递给每个单元格,并在重新加载时设置颜色。

一个非常善良的人帮助我找到了这个解决方案。这里的问题是我忘记了视图的层次结构。

CollectionView 单元格

 override func layoutSubviews() {
        super.layoutSubviews()
           setupBackGround()
    } 
func setupBackGround(){
backgroundColor = isHighlighted ? highlighColor : defaultColor
}

键盘视图控制器


func setColorScheme(_ colorScheme: ColorScheme) {
      let colorScheme = CColors(colorScheme: colorScheme)
     
      for view in subviews {
         func setToRootView(view: UIView) {
                if let cell = view as? KeyboardKeys {
                    cell.tintColor = colorScheme.buttonTextColor
                    cell.defaultColor = colorScheme.keysDefaultColor
                    cell.highlighColor = colorScheme.keysHighlightColor
                    cell.setBackground()
                    return
                }
                guard view.subviews.count > 0 else {
                    return
                }
                view.subviews.forEach(setToRootView(view:))
            }
            setToRootView(view: self)
        }