Ios 如何在集合视图单元格(如App Store)中制作UICollectionView动画?

Ios 如何在集合视图单元格(如App Store)中制作UICollectionView动画?,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我如何实现以下目标: 即使在我滚动浏览时,集合视图也会在集合视图单元格内缓慢移动。您可以使用CollectionKitframework来完成此操作 您还可以在“集合”视图中应用其他一些最佳动画 这一个属于CollectionView中的单元格。您可以通过调用在单元格中手动设置UIImageView的动画 class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Vo

我如何实现以下目标:


即使在我滚动浏览时,集合视图也会在集合视图单元格内缓慢移动。

您可以使用
CollectionKit
framework来完成此操作

您还可以在“集合”视图中应用其他一些最佳动画

这一个属于CollectionView中的单元格。您可以通过调用在单元格中手动设置UIImageView的动画

class func animate(withDuration duration: TimeInterval, 
    animations: @escaping () -> Void)

您可以找到有关Apple document或stackoverflow的更多信息。

我确实使用desire动画创建了一个简单的项目,我没有实现与AppStore中完全相同的元素位置,但我只向您展示了基本动画以及如何实现它。另外,我没有检查
collectionView
何时到达末尾,我只是用100个元素填充它

我确实添加了
GIF
它的帧速率很低,在模拟器上看起来很好,没有延迟

AnimatedCollectionViewController.swift
class

class AnimatedCollectionViewController: UIViewController {

    @IBOutlet private weak var collectionView: UICollectionView!

    private let identifier = String(describing: AnimatedCollectionViewCell.self)
    private var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()

        /// Loading custom `nib`
        let nib = UINib(nibName: identifier, bundle: Bundle.main)
        collectionView.register(nib, forCellWithReuseIdentifier: identifier)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        /// Starting animation
        startAutoScrollCardsCollectionView()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        /// Remove timer from `RunLoop` object
        timer?.invalidate()
        timer = nil // just in case
    }

    private func startAutoScrollCardsCollectionView() {

        /// This method start timer and fire it immediately
        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [unowned self] _ in
            let currentOffset = self.collectionView.contentOffset
            self.collectionView.setContentOffset(CGPoint(x: currentOffset.x + 5, y: currentOffset.y), animated: true)
        }
    }
}

// MARK: - UICollectionViewDataSource extension

extension AnimatedCollectionViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
        return cell
    }
}

// MARK: - UICollectionViewDelegateFlowLayout extension

extension AnimatedCollectionViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: 100)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
    }
}
class AnimatedCollectionViewCell: UICollectionViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()

        contentView.backgroundColor = UIColor.random
        contentView.layer.cornerRadius = 20
    }
}

extension CGFloat {
    static func random() -> CGFloat {
        return CGFloat(arc4random()) / CGFloat(UInt32.max)
    }
}

extension UIColor {
    static var random: UIColor {
        return UIColor(red:   .random(),
                       green: .random(),
                       blue:  .random(),
                       alpha: 1.0)
    }
}
虚拟
AnimatedCollectionViewCell.swift
class

class AnimatedCollectionViewController: UIViewController {

    @IBOutlet private weak var collectionView: UICollectionView!

    private let identifier = String(describing: AnimatedCollectionViewCell.self)
    private var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()

        /// Loading custom `nib`
        let nib = UINib(nibName: identifier, bundle: Bundle.main)
        collectionView.register(nib, forCellWithReuseIdentifier: identifier)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        /// Starting animation
        startAutoScrollCardsCollectionView()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        /// Remove timer from `RunLoop` object
        timer?.invalidate()
        timer = nil // just in case
    }

    private func startAutoScrollCardsCollectionView() {

        /// This method start timer and fire it immediately
        timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [unowned self] _ in
            let currentOffset = self.collectionView.contentOffset
            self.collectionView.setContentOffset(CGPoint(x: currentOffset.x + 5, y: currentOffset.y), animated: true)
        }
    }
}

// MARK: - UICollectionViewDataSource extension

extension AnimatedCollectionViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
        return cell
    }
}

// MARK: - UICollectionViewDelegateFlowLayout extension

extension AnimatedCollectionViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: 100)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
    }
}
class AnimatedCollectionViewCell: UICollectionViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()

        contentView.backgroundColor = UIColor.random
        contentView.layer.cornerRadius = 20
    }
}

extension CGFloat {
    static func random() -> CGFloat {
        return CGFloat(arc4random()) / CGFloat(UInt32.max)
    }
}

extension UIColor {
    static var random: UIColor {
        return UIColor(red:   .random(),
                       green: .random(),
                       blue:  .random(),
                       alpha: 1.0)
    }
}

所以基本上发生的是,我启动一个
计时器
并立即启动。这个计时器调用
completion
0.1秒,在此完成时间内,我更改
setContentOffset.x
收集视图的位置

您可以从这里开始,将自定义布局添加到单元格的位置,并在
collectionView
reach end时进行检查