我使用水平集合制作各种时间轴。对于每个时间块(一个月),我有一个带有UIViews的单元格,每天都有不同的颜色。有些月份增加了30个视图,大约31个视图,大约28个。我无法动态地向每个单元格添加视图,因此它们不会重复或添加到错误的单元格中。
为此,我创建了这个时间轴的简化版本,其中每个月只有1层/视图动态添加 - 我将尝试解决添加可变数量的视图/图层的问题。
我把这个项目作为我所说的最简单的例子:
https://github.com/AlexMarshall12/testTimeline-iOS
以下是ViewController.swift中的代码:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var filledCells: [Int] = []
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.filledCells = [1,28]
collectionView.delegate = self
collectionView.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 28
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! MyCollectionViewCell
print(indexPath.item)
cell.myLabel.text = String(indexPath.item)
if filledCells.contains(indexPath.item) {
let tickLayer = CAShapeLayer()
tickLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.layer.bounds.width, height: cell.layer.bounds.height), cornerRadius: 5).cgPath
tickLayer.fillColor = UIColor(red:0.99, green:0.13, blue:0.25, alpha:0.5).cgColor
cell.layer.addSublayer(tickLayer)
} else {
//updated
let tickLayer = CAShapeLayer()
tickLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.layer.bounds.width, height: cell.layer.bounds.height), cornerRadius: 5).cgPath
tickLayer.fillColor = UIColor(red:0.1, green:0.13, blue:0.98, alpha:0.5).cgColor
cell.layer.addSublayer(tickLayer)
}
return cell
}
}
这个想法是,对于每个indexPath项(每个单元?),它会查看是否包含在self.filledCells数组中:1或28恰好是外边缘,因为为numberOfItemsInSection返回了28个单元格, 1节。所以我想要发生的是每个细胞都是淡蓝色,除了第一和第二 - 浅红色。
但是,您可以在此处看到https://imgur.com/a/KTLn7Cb。当我来回滚动时,细胞被多次填充,有多种颜色的蓝色,红色和紫色,当然还有1和28以外的颜色。
我认为有两个问题。
有关实现这一目标的任何建议吗?
答案 0 :(得分:3)
您忽略了细胞被重复使用的事实。当你更改一个单元格fillColor,并且它被滚动时,滚动的单元格会重新使用该单元格,而你只需将其填充颜色设置为红色,而你没有将其关闭。为每个单元格明确设置fillColor,无论是红色,白色还是清晰的颜色,都不要为所选单元格设置它。
答案 1 :(得分:2)
每次在表格视图单元格或集合视图单元格中添加视图或图层总是一个坏主意。当您重复使用单元格时,无需一次又一次地创建 tickLayer 。将tickLayer作为全局变量,在MyCollectionViewCell中的awakeFromNib函数中初始化它,然后在cellForRow函数中更改其填充颜色。
答案 2 :(得分:0)
向单元格添加/删除视图不是一个好主意。 有两种方法可以完成此任务: ①通过子视图创建不同的单元格; ②创建一个通用单元格并通过隐藏和布局控制子视图的显示,并在获得具有新数据的单元格时进行更新。
答案 3 :(得分:0)
再加上@Owen Hartnett关于单元格可重用性的说法,我想指出你每次都在重新创建图层!这相当于创建子视图。
每次遇到cellForItemAt
函数内的单元格时,您还应检查是否存在预先添加的图层。像(在语法上不完美的Swift,但伪代码):
let bLayerFound = false;
for (layer: CALayer in cell.layer.sublayers)
{
if (layer.name.equals("mylayer"))
{
let shapeLayer = layer as! CAShapeLayer
bLayerFound = true;
//set layer properties based on your business logic, as you don't know what this cell is holding due to reuse
shapeLayer.path = //path
shapeLayer.fillColor = //color
}
}
if (bLayerFound == false)
{
//create layer here, again
let tickLayer = CAShapeLayer()
//set layer properties based on your business logic, as you don't know what this cell is holding due to reuse
tickLayer.path = //path
tickLayer.fillColor = //color
tickLayer.name = "mylayer"
cell.layer.addSublayer(tickLayer)
}
其他一些警告:
cell.contentView
,而不是cell
本身。UICollectionViewCell
子类。如果没有子类,可能是一个单独的函数,以免混淆cellForItemAt
带有令人讨厌的if-else逻辑。