Как изменить цвет ячеек collectionview в зависимости от темы устройства (следуя моей цветовой схеме)

#ios #swift #colors #uicollectionview

#iOS #swift #Цвет #uicollectionview

Вопрос:

Обзор:

Я создаю расширение клавиатуры, используя collectionviews. Я хочу, чтобы ячейки меняли цвет в зависимости от темы устройства (светлый / темный). На данный момент, когда я устанавливаю цветовую схему для своих ячеек collectionview, они не работают. Я отмечаю проблемные части своего кода комментарием «///».

Ресурсы:

Я нашел этот проект RayWenderlich, и мне понравилось, как они обрабатывают изменения цвета, поэтому я скопировал его.

Мой код:

У меня есть 3 класса:

  1. KeyboardViewController
  2. Пользовательский вид, содержащий кнопки клавиатуры
  3. Пользовательские ячейки collectionview

Ячейка 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
      }
      }
    }
    
}

  

Color scheme struct

 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  
        }
    }
}
  

KeyboardViewController

 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 в зависимости от темы устройства, следуя моей цветовой схеме?

Ответ №1:

Вам действительно следует перезагрузить представление коллекции, а не пытаться найти вложенные представления, которые являются ключами, и обновлять их.

Передайте модель colorScheme для каждой ячейки и задайте цвета в результате перезагрузки.

Комментарии:

1. Да, я думаю, что @Jay прав. Вам нужно перезагрузить представление коллекции (вашу пользовательскую клавиатуру) и для простоты сделать цвет вычисляемым свойством, которое дает результат, проверяя тему.

Ответ №2:

Очень добрый парень помог мне и нашел это решение. Проблема здесь в том, что я забыл иерархию представления.

Ячейка CollectionView

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

KeyboardViewController

 
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)
        }