微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在自定义flowLayout中的uicollectionview中平滑动画过渡单元格

如何解决如何在自定义flowLayout中的uicollectionview中平滑动画过渡单元格

我想创建一个应用程序,该应用程序显示一系列带有标题(现在我有空圆圈)的照片,这些照片在水平 uicollectionview 中排列。我想让一个更大的圆圈显示在屏幕的中心,但线条中的其余圆圈更小并带有阴影。我通过为 uicollectionview 创建自己的布局来做到这一点。但是我有一个问题,我不知道如何解决。我希望圆圈之间的过渡平滑动画。这是我所做的example

我想实现这样的目标:gif

我知道有一些库和框架可以做到这一点,但我想自己做。 这是我的代码

class FlowViewController: UIViewController {

    let cellWidth : CGFloat = 275
    let cellHeight : CGFloat = 300
    let cellSpacing : CGFloat = 10
    
    private let circleCollectionView = UICollectionView(frame: CGRect.zero,collectionViewLayout: UICollectionViewFlowLayout.init())
    private let layout = myCarouselFlowLayout()
    private let collectionViewCellIdentifier = "PositionCollectionViewCell"
    
    private var circles : [myCircle] = {
        let pok1 = myCircle(name: "Bl4")
        let pok2 = myCircle(name: "Bl3")
        let pok3 = myCircle(name: "Bli")
        let pok4 = myCircle(name: "Bl0")
        let pok5 = myCircle(name: "Lal")
        let pok6 = myCircle(name: "Te")
        let pok7 = myCircle(name: "wTW")
        let pok8 = myCircle(name: "H3RHG")
        return [pok1,pok2,pok3,pok4,pok5,pok6,pok7,pok8]
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = #colorLiteral(red: 0.4745098054,green: 0.8392156959,blue: 0.9764705896,alpha: 1)
        
        view.addSubview(circleCollectionView)
        configureCollectionView()
        
        print(circles.count)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        configureCollectionViewLayoutItemSize()
    }
    
    func configureCollectionView(){
        
        layout.scrollDirection = .horizontal
        layout.itemSize = CGSize(width: cellWidth,height: cellHeight)
        layout.minimumLinespacing = cellSpacing
        
        //set layout
        circleCollectionView.setCollectionViewLayout(layout,animated: true)
        //set delegates
        setTableViewDelegates()
        //register cells
        circleCollectionView.register(CircleCollectionViewCell.self,forCellWithReuseIdentifier: collectionViewCellIdentifier)
        //set contraits
        circleCollectionView.translatesAutoresizingMaskIntoConstraints = false
        circleCollectionView.heightAnchor.constraint(equalToConstant: cellHeight).isActive = true
        circleCollectionView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        circleCollectionView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        circleCollectionView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        
        circleCollectionView.backgroundColor = .clear
        circleCollectionView.decelerationRate = .fast


        
    }
    
    func calculateSectionInset() -> CGFloat { // should be overridden
        let viewWith = UIScreen.main.bounds.size.width
        return ( viewWith - cellWidth ) / 2
    }
    private func configureCollectionViewLayoutItemSize() {
        let inset: CGFloat = calculateSectionInset()
        layout.sectionInset = UIEdgeInsets(top: 0,left: inset,bottom: 0,right: inset)

        layout.itemSize = CGSize(width: layout.collectionView!.frame.size.width - inset * 2,height: layout.collectionView!.frame.size.height)
    }

}

extension FlowViewController: UICollectionViewDelegate,UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
        circles.count
    }
    
    func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellIdentifier,for: indexPath) as? CircleCollectionViewCell else {
            fatalError("Bad instance of FavoritesCollectionViewCell")
        }
        cell.nameLabel.text = circles[indexPath.row].name
        return cell
    }
    
    
    func setTableViewDelegates(){
        circleCollectionView.delegate = self
        circleCollectionView.dataSource = self
    }
    
    func collectionView(_ collectionView: UICollectionView,didSelectItemAt indexPath: IndexPath) {
        print(circles.count)
    }
    


}

extension FlowViewController: UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeforItemAt indexPath: IndexPath) -> CGSize {
        let width = cellWidth
        let height = cellHeight
        
         return CGSize(width: width,height: height)
     }
    



}
class myCarouselFlowLayout: UICollectionViewFlowLayout,UICollectionViewDelegateFlowLayout {
    
    private let fadeFactor: CGFloat = 0.5
    
    override var collectionViewContentSize: CGSize {
        super.collectionViewContentSize
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        super.layoutAttributesForElements(in: rect)?.map {
            self.layoutAttributesForItem(at: $0.indexPath)!
        }
    }
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let superValue = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return nil }
        
        guard let cv = collectionView else { return nil }
        let collectionMidPoint = CGPoint(x: cv.bounds.midX,y: cv.bounds.midY)
        let itemmidPoint = superValue.center

        let distance = abs(itemmidPoint.x - collectionMidPoint.x)

        if distance > 100 {
            UIView.animate(withDuration: 0.2) {
                superValue.alpha = self.fadeFactor
                superValue.transform = CGAffineTransform(scaleX: 0.8,y: 0.8)
                cv.layoutIfNeeded()
            }
        }
        return superValue
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        true
    }

    var veLocityThresholdPerPage: CGFloat = 2
    
    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint,withScrollingVeLocity veLocity: CGPoint) -> CGPoint {
            guard let collectionView = collectionView else { return proposedContentOffset }
            
            let pageLength: CGFloat
            let approxPage: CGFloat
            let currentPage: CGFloat
            
                pageLength = (self.itemSize.width + self.minimumLinespacing)
                approxPage = collectionView.contentOffset.x / pageLength
                
        
            currentPage = round(approxPage)
            
            if veLocity.x == 0 {
                return CGPoint(x: currentPage * pageLength,y: 0)
            }
            
            var nextPage: CGFloat = currentPage + (veLocity.x > 0 ? 1 : -1)
            
            let increment = veLocity.x / veLocityThresholdPerPage
            
        nextPage += round(increment)
            
            
        return CGPoint(x: nextPage * pageLength,y: 0)
}



请给我一些关于我应该在哪里以及如何在上面使用动画的建议?我应该用 UIView.animate 还是其他东西来做?我知道我需要使用 layoutIfNeeded() 来为约束设置动画,但它不起作用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。