我有一个collectionView,我正在整理一个时间表。在水平collectionView中有许多瘦细胞-每个细胞代表1天。这是项目代码:https://github.com/AlexMarshall12/singleDayTimeline.git
这是viewController:
let cellIdentifier = "DayCollectionViewCell"
class ViewController: UIViewController, UICollectionViewDataSource,UICollectionViewDelegate {
@IBOutlet weak var button: UIButton!
var dates = [Date?]()
var startDate: Date?
var endDate: Date?
private var selectedIndexPath: IndexPath?
@IBOutlet weak var daysCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
daysCollectionView.register(UINib.init(nibName: "DayCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: cellIdentifier)
let allDates = Helper.generateRandomDate(daysBack: 900, numberOf: 10)
self.dates = allDates.sorted(by: {
$0!.compare($1!) == .orderedAscending
})
self.startDate = Calendar.current.startOfDay(for: dates.first as! Date)
self.endDate = dates.last!
self.dates = Array(dates.prefix(upTo: 1))
daysCollectionView.delegate = self
daysCollectionView.dataSource = self
}
var onceOnly = false
internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !onceOnly {
//let lastDateIndexPath = IndexPath(row: dates.count - 1,section: 0)
let lastDate = dates.last
let lastDayIndex = lastDate!?.interval(ofComponent: .day, fromDate: startDate!)
let lastDayCellIndexPath = IndexPath(row: lastDayIndex!, section: 0)
self.daysCollectionView.scrollToItem(at: lastDayCellIndexPath, at: .left, animated: false)
self.selectedIndexPath = lastDayCellIndexPath
self.daysCollectionView.reloadItems(at: [lastDayCellIndexPath])
onceOnly = true
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let days = self.endDate!.days(from: self.startDate!)
if days <= 150 {
return 150
} else {
print(days,"days")
return days + 1
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = daysCollectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! DayCollectionViewCell
let cellDate = Calendar.current.date(byAdding: .day, value: indexPath.item, to: self.startDate!)
if let selectedRow = selectedIndexPath {
cell.reloadCell(selectedRow==indexPath)
} else {
cell.reloadCell(false)
}
if Calendar.current.component(.day, from: cellDate!) == 15 {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM"
let monthString = dateFormatter.string(from: cellDate!)
cell.drawMonth(month: monthString)
}
if Calendar.current.component(.day, from: cellDate!) == 1 && Calendar.current.component(.month, from: cellDate!) == 1 {
print("drawYEAR")
cell.drawYear(year:Calendar.current.component(.year, from: cellDate!))
}
if self.dates.contains(where: { Calendar.current.isDate(cellDate!, inSameDayAs: $0!) }) {
print("same")
cell.backgroundColor = UIColor.red
}
//cell.backgroundColor = UIColor.blue
return cell
}
@IBAction func buttonPressed(_ sender: Any) {
let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
let randomDate = self.dates[randomIndex]
let daysFrom = randomDate?.days(from: self.startDate!)
let indexPath = IndexPath(row: daysFrom!, section: 0)
self.selectedIndexPath = indexPath;
//daysCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally)
daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
daysCollectionView.reloadData()
}
}
请注意,当调用buttonPressed函数时,“ selectedIndexPath”将更改。然后下一次调用cellForItemAt时,它会执行cell.reloadCell,如果indexPath是这个selectedIndexPath,它将取消隐藏arrowImageView(见下文)
class DayCollectionViewCell: UICollectionViewCell {
...
func reloadCell(_ isSelected:Bool){
arrowImage.isHidden = !isSelected
}
}
这在按下按钮时有效,但是我试图使其在willDisplayCell回调中起作用。您可以看到,在此回调中,我基本上只是获取最新(最新)日期并滚动到该日期,然后将SelectedIndexPath设置为该indexPath。现在,我需要一种使箭头在该单元格上绘制的方法。
如您所见,直到滚动时,它才显示箭头。我认为正在发生的事情是,当您滚动调用足够的cellForItemAt时,我们就知道了。但是,如何使willDisplayCell成功完成相同的操作,从而从初始启动时加载箭头?
答案 0 :(得分:2)
在您的 viewDidLoad 中,您似乎正在初始化日期, startDate 和 endDate 。
因此,在设置完这些变量后,您可以使用可用数据设置 selectedIndexPath 。然后,调用 cellForItem 方法时,其中的代码将自动处理箭头的可见性。
在初始化三个变量之后,立即将代码放置在 viewDidLoad 中。
if let startDate = startDate,
let lastDayIndex = dates?.last?.interval(ofComponent: .day, fromDate: startDate) {
selectedIndexPath = IndexPath(row: lastDayIndex, section: 0)
}
您无需在 willDisplayCell 中进行处理,也无需使用 onceOnly 布尔值。
答案 1 :(得分:1)
我添加一个新答案是因为我注意到其他答案的一些不完整细节。
在viewDidLoad中,有一个奇怪的代码:
self.dates = Array(dates.prefix(upTo: 1))
我认为这是一个测试代码。因此结果将总共只有一个小节。不管是什么原因,都应该在该代码之后添加随机或最后一个随机代码。
let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
let randomDate = self.dates[randomIndex]
let daysFrom = randomDate?.days(from: self.startDate!)
let indexPath = IndexPath(row: daysFrom!, section: 0)
self.selectedIndexPath = indexPath;
// daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
请注意,我评论了最后一个。如果只有一个条,就足够了,但是如果有多个,则应该将scrollToItem添加到其他位置,因为当前collectionView尚未初始化。
一个想法的地方与willDisplay中的原始帖子一样,这很容易实现。唯一的问题是willDisplay的时间跨度很短,因此无法在那里重新加载整个collectionData。
但是,在此处滚动到一个indexPath很好。就像下面的代码一样。
var onceOnly = false
internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if (!onceOnly){
self.daysCollectionView.scrollToItem(at: self.selectedIndexPath!, at: .left, animated: false)
onceOnly = true
}
}
还有一个调用两个函数(selectIndex和滚动)的好地方,如下所示:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let randomIndex = Int(arc4random_uniform(UInt32(self.dates.count)))
let randomDate = self.dates[randomIndex]
let daysFrom = randomDate?.days(from: self.startDate!)
let indexPath = IndexPath(row: daysFrom!, section: 0)
if self.selectedIndexPath != nil {
daysCollectionView.reloadItems(at: [self.selectedIndexPath!])
}
self.selectedIndexPath = indexPath;
daysCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
daysCollectionView.reloadItems(at: [indexPath])
}
现在我认为这是一个完整的答案。希望对您有所帮助。