如何根据设备主题更改 collectionview 单元格颜色(按照我的配色方案)
How to change collectionview cells color based on device theme (following my color scheme)
概览:
我正在使用集合视图构建键盘扩展。我希望单元格根据设备主题 (light/dark) 改变颜色。目前,当我为我的 collectionview 单元格设置配色方案时,它们不起作用。我用“///”注释标记了我的代码中有问题的部分。
资源:
我找到了 this RayWenderlich project,我喜欢他们处理颜色变化的方式,所以我复制了它。
我的代码:
我有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)
}
概览:
我正在使用集合视图构建键盘扩展。我希望单元格根据设备主题 (light/dark) 改变颜色。目前,当我为我的 collectionview 单元格设置配色方案时,它们不起作用。我用“///”注释标记了我的代码中有问题的部分。
资源:
我找到了 this RayWenderlich project,我喜欢他们处理颜色变化的方式,所以我复制了它。
我的代码:
我有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)
}