如何为CollectionView的scrollToItem方法添加闭包实现按钮可靠隐藏?
解决CollectionView滚动到顶后按钮隐藏不生效的问题
你的问题核心在于:scrollToItem(at:animated:) 是异步执行动画的,你在调用它之后立刻设置 bBackToTop.isHidden = true,此时滚动动画可能还没开始或完成,导致按钮隐藏的时机不对,偶尔需要点击两次才能生效。下面提供两种可靠的解决方案,让按钮在滚动动画完成后再隐藏:
方法一:使用CATransaction捕获动画完成事件
Core Animation的事务机制可以监听UIKit动画的完成状态,非常适合这个场景:
@IBAction func backToTopClicked(_ sender: Any) { // 先禁用按钮,避免重复点击触发多次滚动 bBackToTop.isEnabled = false CATransaction.begin() // 设置动画完成后的闭包 CATransaction.setCompletionBlock { [weak self] in guard let self = self else { return } self.bBackToTop.isHidden = true self.bBackToTop.isEnabled = true } // 执行滚动到顶操作 self.productCollectionView?.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: true) CATransaction.commit() }
说明:
[weak self]是为了避免循环引用,保证ViewController能正常释放- 禁用按钮可以防止用户在滚动动画过程中重复点击,彻底解决“需要点击两次”的问题
- 闭包会在滚动动画完全结束后执行,此时再隐藏按钮时机完全准确
方法二:利用UIScrollView代理监听动画结束
因为UICollectionView继承自UIScrollView,我们可以用UIScrollViewDelegate的专用方法监听代码触发的滚动动画结束:
步骤1:让ViewController遵守UIScrollViewDelegate协议
class YourViewController: UIViewController, UICollectionViewDelegate { // ...你的现有代码 }
步骤2:设置CollectionView的代理
在viewDidLoad中添加:
override func viewDidLoad() { super.viewDidLoad() productCollectionView.delegate = self }
步骤3:实现代理方法并处理按钮隐藏
@IBAction func backToTopClicked(_ sender: Any) { bBackToTop.isEnabled = false self.productCollectionView?.scrollToItem(at: IndexPath(item: 0, section: 0), at: .top, animated: true) } func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { // 确认是我们的productCollectionView触发的滚动 if scrollView === productCollectionView { bBackToTop.isHidden = true bBackToTop.isEnabled = true } }
说明:
scrollViewDidEndScrollingAnimation只会在代码触发的滚动动画结束时调用,用户手动滚动不会触发这个方法,完全符合我们的需求- 这种方法更适合需要处理多个滚动相关逻辑的场景,扩展性更强
你可以根据自己的代码结构选择其中一种方法,两种都能彻底解决按钮隐藏时机不准确的问题。
内容的提问来源于stack exchange,提问作者TheTravloper
相关产品推荐
相关产品推荐

