页面加载时滚动后如何访问 UICollectionView 中的特定单元格?
Posted
技术标签:
【中文标题】页面加载时滚动后如何访问 UICollectionView 中的特定单元格?【英文标题】:How to access specific cell in UICollectionView after scrolling when page loads? 【发布时间】:2018-09-06 20:27:15 【问题描述】:我正在尝试像这样构建一个时间线:
时间轴中的每个单元格代表一个月,因此 May 是水平 collectionView 中的最后一个单元格。我想要的是当 collectionView 加载时,如果它不可见,它会自动滚动到可能,然后调用单元格上的特定函数来绘制箭头。我用来尝试执行此操作的代码如下。
override func viewDidLoad()
super.viewDidLoad()
self.timeline.register(UINib(nibName: "TimelineMonthViewCell", bundle: nil), forCellWithReuseIdentifier: "TimelineMonthViewCell")
self.collectionView.register(UINib(nibName: "PostCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "PostCollectionViewCell")
pageControl.hidesForSinglePage = true
self.navigationItem.largeTitleDisplayMode = .never
UserService.posts(for: User.current,tagString: self.selectedTagTitles.first!) (postStuff) in
self.posts = postStuff.0
self.postIds = postStuff.1
self.timeline.dataSource = self
self.collectionView.dataSource = self
self.timeline.delegate = self
self.collectionView.delegate = self
self.firstPostDate = self.posts.first?.timeStamp
self.currentPostDate = self.posts.last?.timeStamp
override open func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
let indexToScrollTo = IndexPath(row: self.posts.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
let firstPostDate = self.posts.first?.timeStamp
let diff = self.posts.last?.timeStamp.months(from: (firstPostDate?.startOfMonth())!)
//self.currentPostMonth = diff
let monthCellIndexPath = IndexPath(row: diff!, section: 0)
self.timeline.scrollToItem(at: monthCellIndexPath, at: .centeredHorizontally, animated: false)
let months = self.posts.last?.timeStamp.months(from: (self.posts.first?.timeStamp.startOfMonth())!)
print("cells are",self.timeline.indexPathsForVisibleItems)
print(months,"cell months")
if let optionalCell = self.timeline.cellForItem(at: IndexPath(row: months!, section: 0))
let cell = optionalCell as! TimelineMonthViewCell
let day = Calendar.current.component(.day, from: self.currentPostDate!)
cell.drawArrow(day: day)
else
print("cell out of range")
这几乎可以工作,除了两个问题。
首先,初始单元格会在自动滚动到最后一个单元格之前闪烁。我认为这是因为我使用的是 viewDidAppear 而不是 viewWillAppear。但是,当我使用 viewWillLoad 时,应用程序崩溃并出现错误:Thread 1: EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff8)
其次,打印出来的self.timeline.indexPathsForVisibleItems为:[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]]。因此,它查看的是前 5 个而不是它刚刚滚动到的最后 5 个。然后它找不到单元格:“单元格超出范围”,因为索引约为 28(最后一个单元格)。
那么我怎样才能让它自动滚动到最后一个单元格并正确找到它呢?
【问题讨论】:
【参考方案1】:不要将这些行设置在当前位置
self.timeline.dataSource = self
self.collectionView.dataSource = self
self.timeline.delegate = self
self.collectionView.delegate = self
在viewDidLoad
之上可能会更好,以利用加载vc时的第一次自动重新加载,也在他们的位置插入
self.timeline.reloadData()
self.collectionView.reloadData()
你可以在里面插入滚动代码
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
如果您当前的 for 循环不是异步的,则在 ViewDidAppear
内
【讨论】:
你能显示你正在考虑的代码吗?我无法将 dataSource 和委托移动到 viewDidLoad 的顶部,因为我的帖子对象尚未创建。如果您想查看更新的代码,我还删除了异步调度以简化问题...【参考方案2】:我建议将滚动代码移至viewWillAppear
。这样,它在视图显示之前完成,但在所有内容都准备好查看之后完成。
override open func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
let indexToScrollTo = IndexPath(row: self.posts.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
let firstPost = self.posts.first?.timeStamp
let firstOfFirstMonth = firstPost?.startOfMonth()
let diff = self.posts.last?.timeStamp.months(from: firstOfFirstMonth!)
//self.currentPostMonth = diff
let monthCellIndexPath = IndexPath(row: diff!, section: 0)
self.timeline.scrollToItem(at: monthCellIndexPath, at: .centeredHorizontally, animated: false)
【讨论】:
这使我的应用程序崩溃,并出现错误代码:线程 1:EXC_BAD_ACCESS(代码=1,地址=0xfffffffffffffff8)在此行:self.collectionView.scrollToItem(at:indexToScrollTo,at:.left,动画:假) 嗯。尝试移动它做 viewDidAppear。运气好的话,你不会看到它更新。 确实有效!但是我仍然遇到相同的问题,即找不到单元格,因此无法绘制箭头 如果您查看更新后的问题,您会看到我采纳了您的建议,但仍然存在在 viewDidAppear 中找不到单元格索引的问题。实际上,indexesForVisibleCells 似乎打印了原始索引(滚动发生之前的索引) 您需要处理cellForItemAt
中的绘图,这确实是第二个问题。将其作为一个不同的问题发布,我会尽力回答。以上是关于页面加载时滚动后如何访问 UICollectionView 中的特定单元格?的主要内容,如果未能解决你的问题,请参考以下文章
仅在滚动(分页)后显示的数据是不是是加载页面时 dom 的一部分?