You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UICollectionView编程滚动异常:修复后出现奇怪吸附效果求助

问题描述

我尝试从另一个UICollectionView中通过代码滚动到目标UICollectionView的指定索引,但滚动操作未生效。已确认触发滚动的代码已执行,传入的索引正确,且尝试滚动后contentOffset值未发生变化,希望找出滚动失效的原因及解决方法。

更新
我通过先设置isPagingEnabled为false再改为true的方式修复了滚动失效问题,但现在出现了如动图所示的奇怪吸附效果。

奇怪的吸附效果

相关代码

CollectionViewController

class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, MenuControllerDelegate {
    
    func didTapMenuItem(index: Int) {
        collectionView.isPagingEnabled = false
        collectionView.scrollToItem(
            at: IndexPath(item: index, section: 0),
            at: .centeredHorizontally,
            animated: true
        )
        collectionView.isPagingEnabled = true
    }
    
    fileprivate let menuController = MenuController(collectionViewLayout: UICollectionViewFlowLayout())

    override func viewDidLoad() {
        super.viewDidLoad()

        
        menuController.delegate = self
        menuController.collectionView.selectItem(at: [0,0], animated: true, scrollPosition: .centeredHorizontally)
        
        if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
            layout.scrollDirection = .horizontal
            layout.minimumLineSpacing = 0
         
        }
        
        setupLayout()
        
        collectionView.register(MainCell.self, forCellWithReuseIdentifier: "main")
        collectionView.isPagingEnabled = true
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.allowsSelection = true
    }
    fileprivate func setupLayout(){
        view.addSubview(menuController.view)
        
        menuController.view.anchor(top: view.safeAreaLayoutGuide.topAnchor, leading: view.leadingAnchor, bottom: nil, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 0), size: .init(width: 0, height: 70))
        
        collectionView.anchor(top: menuController.view.bottomAnchor, leading: view.leadingAnchor, bottom: view.bottomAnchor, trailing: view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 0))
    }
    
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let x = scrollView.contentOffset.x
        let offset = x / 2
        menuController.menuBar.transform = CGAffineTransform(translationX: offset, y: 0)
    }

    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        let x = targetContentOffset.pointee.x
        let item = x / view.frame.width
        let indexPath = IndexPath(item: Int(item), section: 0)
        menuController.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "main", for: indexPath) as! MainCell
        
        if indexPath.item == 0 {
            cell.backgroundColor = .blue
        }else if indexPath.item == 1 {
            cell.backgroundColor = .green
        }
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let height = view.frame.height
        let width = view.frame.width
        return .init(width: width, height: height - 70)
    }
}
protocol MenuControllerDelegate {
    
    func didTapMenuItem(index: Int)
}
class MenuController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    
    fileprivate let menuItems = ["Today", "News"]
    
    var delegate: MenuControllerDelegate?
    
    let menuBar: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 35
       return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        collectionView.backgroundColor = .darkGray
        collectionView.layer.cornerRadius = 35
        
        collectionView.register(MenuCell.self, forCellWithReuseIdentifier: "cell")
        
        if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
            layout.scrollDirection = .horizontal
            layout.minimumLineSpacing = 0
            layout.minimumInteritemSpacing = 0
        }
        
        
        view.addSubview(menuBar)
        menuBar.anchor(top: view.topAnchor, leading: view.leadingAnchor, bottom: view.bottomAnchor, trailing: nil, size: .init(width: 0, height: 70))
        menuBar.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/2).isActive = true
 
    }
    
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        
        let x = view.frame.width / 2 * CGFloat(indexPath.item)
        UIView.animate(withDuration: 0.5, delay: 0,usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
            
            self.menuBar.transform = CGAffineTransform(translationX: x, y: 0)
        })
        delegate?.didTapMenuItem(index: indexPath.item)
    }
    
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return menuItems.count
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MenuCell
        cell.label.text = menuItems[indexPath.item]
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        let width = view.frame.width
        return .init(width: width / 2, height: view.frame.height)
    }
    
}

内容的提问来源于stack exchange,提问作者GILL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 15:42:27