CollectionView 滚动到新插入的项目
CollectionView scroll to newly inserted item
我有一个由 NSFetchedResultsController 驱动的 CollectionView。
CollectionViewLayout 是按名称升序排列的水平 "carousel" 单元格布局。
新项目插入了自定义动画。
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseOut, animations: {
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
})
)
...
它可以工作,但动画有点问题,并且滚动是同时发生的。
我想滚动到项目然后用自定义动画插入它,但是如果我在插入它之前滚动到项目应用程序崩溃。
在这里正确的做法是什么?
谢谢
通过查看函数,我可以想象您看到的故障是 CollectionView 向前滚动然后橡皮筋滚动/"teleporting" 向后滚动。
我认为这可能是因为您试图同时 运行 两个动画。
你的第一个动画,UIView.animate(),动画滚动到新插入的项目;但是,当您调用 collectionView?.scrollToItem() 时,您也会对其进行动画处理(见下文)
self.collectionView?.scrollToItem(..., animated: true) <--
这可能就是它不起作用的原因;您正在尝试制作动画。
尝试将 animated 设置为 false,看看是否可以解决问题。
我要尝试的第一件事是将 animate(withDuration:delay:options:animations:completion:)
替换为 performBatchUpdates(_:completion:)
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.performBatchUpdates({
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
})
…
}
如果这仍然给您带来问题,那么您可以在下一个 运行 循环中调用卷轴。
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.performBatchUpdates({
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
DispatchQueue.main.async { // Defer to next runlop.
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
}
})
…
}
最后,您可以尝试只对滚动部分进行动画处理。
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.reloadItems(at: [newIndexPath]) // reload without animating.
DispatchQueue.main.async { // Defer to next runlop.
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
}
…
}
我有一个由 NSFetchedResultsController 驱动的 CollectionView。
CollectionViewLayout 是按名称升序排列的水平 "carousel" 单元格布局。
新项目插入了自定义动画。
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseOut, animations: {
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
})
)
...
它可以工作,但动画有点问题,并且滚动是同时发生的。
我想滚动到项目然后用自定义动画插入它,但是如果我在插入它之前滚动到项目应用程序崩溃。
在这里正确的做法是什么?
谢谢
通过查看函数,我可以想象您看到的故障是 CollectionView 向前滚动然后橡皮筋滚动/"teleporting" 向后滚动。
我认为这可能是因为您试图同时 运行 两个动画。 你的第一个动画,UIView.animate(),动画滚动到新插入的项目;但是,当您调用 collectionView?.scrollToItem() 时,您也会对其进行动画处理(见下文)
self.collectionView?.scrollToItem(..., animated: true) <--
这可能就是它不起作用的原因;您正在尝试制作动画。 尝试将 animated 设置为 false,看看是否可以解决问题。
我要尝试的第一件事是将 animate(withDuration:delay:options:animations:completion:)
替换为 performBatchUpdates(_:completion:)
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.performBatchUpdates({
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
})
…
}
如果这仍然给您带来问题,那么您可以在下一个 运行 循环中调用卷轴。
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.performBatchUpdates({
self.collectionView?.insertItems(at: [newIndexPath])
}, completion: { finished in
DispatchQueue.main.async { // Defer to next runlop.
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
}
})
…
}
最后,您可以尝试只对滚动部分进行动画处理。
func controller(controller: NSFetchedResultsController,
didChangeObject anObject: AnyObject,
atIndexPath indexPath: NSIndexPath?,
forChangeType type: NSFetchedResultsChangeType,
newIndexPath: NSIndexPath?)
{
if type == NSFetchedResultsChangeType.Insert {
println("Insert Object: \(newIndexPath)")
self.collectionView?.reloadItems(at: [newIndexPath]) // reload without animating.
DispatchQueue.main.async { // Defer to next runlop.
self.collectionView?.scrollToItem(at: newIndexPath, at: .centeredHorizontally, animated: true)
}
…
}