Как добиться флип-анимации с помощью UICollectionViewCompositionalLayout

Не уверен, как добиться анимации переворота, подобной короткой, но с использованием нового UICollectionViewDelegateFlowLayout. Ниже приведен код, который я пробовал пока безрезультатно. Благодарность

import UIKit

class ViewController: UIViewController {
    private var collectionView: UICollectionView!
    override func viewDidLoad() {
        super.viewDidLoad()
        let flowLayout = createCompositionalLayout()
        self.collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
        collectionView.register(HostingCollectionViewCell.self, forCellWithReuseIdentifier: "HostingCollectionViewCell")
        collectionView.delegate = self
        collectionView.dataSource = self

        collectionView.isDirectionalLockEnabled = true
        collectionView.isPagingEnabled = true
        collectionView.showsVerticalScrollIndicator = false
        collectionView.contentInsetAdjustmentBehavior = .never
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.alwaysBounceHorizontal = false
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.backgroundColor = .secondarySystemFill

        self.view.addSubview(collectionView!)
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            ])
        
        self.view.backgroundColor = .tertiarySystemBackground
    }
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        let maxScale = 1.0
        let minScale = 0.7
        
        section.visibleItemsInvalidationHandler = { items, offset, env in
            for (index, item) in items.enumerated() {
                if (index == 1) {
                    let distanceFromTop = (item.frame.midY - offset.y) - env.container.contentSize.height / 2.0
                    let alpha = 1 - (distanceFromTop / env.container.contentSize.height ) * 1.0
                    item.transform = CGAffineTransform.identity()
                    item.zIndex = 0
                    item.alpha = alpha
                } else {
                    item.alpha = 1
                    item.zIndex = 1
                    item.transform = .identity
                }
            }
        }
        
        let config = UICollectionViewCompositionalLayoutConfiguration()
        config.scrollDirection = .vertical

        let layout = UICollectionViewCompositionalLayout(section: section, configuration: config)
        return layout
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 40
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HostingCollectionViewCell", for: indexPath) as! HostingCollectionViewCell
        let render = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 200))
        cell.mastImage.image = render.image(actions: { (ctx) in
            UIImage(named: "bookmark")?.draw(in: CGRect(origin: .zero, size: .zero))
        })
        cell.titleLbl.text = "If you need support post Rotation Support for Autosizing, Full-width UICollectionViewCells in Swift 4. \(indexPath.row)"
        cell.descriptionLbl.text = "As of August 2020, we Americans are embroiled in an intensifying cold civil war, says Julian Zelizer . Zelizer: The left is an ominous force thanks to a mix of cynical calculation, intimidation, and strong-arm tactics . The left doesn't want peace and stability 2014 unless it's on its terms, which would amount to a statist construct, meaning jackhammering the American foundation and evisceration of Western values."

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return collectionView.bounds.size
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        NSLog("Geting called")
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        NSLog("Geting called")
        return 0
    }
}

class HostingCollectionViewCell: UICollectionViewCell {
    var titleLbl: UILabel = {
        let titleLabel = UILabel()
        titleLabel.font = UIFont(name: "Optima-Bold", size: UIFontMetrics.default.scaledValue(for: 20))
        titleLabel.numberOfLines = 4
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        return titleLabel
    }()

    var descriptionLbl: UILabel = {
        let descriptionLbl = UILabel()
        descriptionLbl.font = UIFont(name: "LaoSangamMN", size: UIFontMetrics.default.scaledValue(for: 18))
        descriptionLbl.numberOfLines = 0
        descriptionLbl.translatesAutoresizingMaskIntoConstraints = false
        return descriptionLbl
    }()

    var mastImage: UIImageView = {
        let _img = UIImageView()
        _img.translatesAutoresizingMaskIntoConstraints = false
        _img.backgroundColor = .blue
        _img.contentMode = .scaleAspectFit
        _img.clipsToBounds = true
        return _img
    }()

    var bottomToolbar: UIView = {
        let toolbar = UIView()
        toolbar.backgroundColor = .tertiarySystemFill
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        return toolbar
    }()

    var imgHeightConstraint: NSLayoutConstraint?
    var aspectRation = 1.0 {
        didSet {
            if(imgHeightConstraint != nil) {
                mastImage.removeConstraint(imgHeightConstraint!)
            }
            imgHeightConstraint = mastImage.heightAnchor.constraint(lessThanOrEqualTo: mastImage.widthAnchor, multiplier: CGFloat(1 / aspectRation))
            NSLayoutConstraint.activate([imgHeightConstraint!])
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentView.backgroundColor = .secondarySystemBackground
        self.contentView.addSubview(self.titleLbl)
        self.contentView.addSubview(self.mastImage)
        self.contentView.addSubview(self.descriptionLbl)
        self.contentView.addSubview(self.bottomToolbar)

        NSLayoutConstraint.activate([
            self.mastImage.topAnchor.constraint(equalTo: self.contentView.safeAreaLayoutGuide.topAnchor),
            self.mastImage.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
            self.mastImage.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
            ])

        NSLayoutConstraint.activate([
            self.titleLbl.topAnchor.constraint(equalTo: self.mastImage.bottomAnchor, constant: 8),
            self.titleLbl.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10),
            self.titleLbl.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10),
            ])

        NSLayoutConstraint.activate([
            self.descriptionLbl.topAnchor.constraint(equalTo: self.titleLbl.bottomAnchor, constant: 8),
            self.descriptionLbl.bottomAnchor.constraint(lessThanOrEqualTo: bottomToolbar.topAnchor, constant: -10),
            self.descriptionLbl.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10),
            self.descriptionLbl.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10),
            ])

        let bottom = (UIApplication.shared.windows.first { $0.isKeyWindow }?.safeAreaInsets.bottom) ?? 0

        NSLayoutConstraint.activate([
            self.bottomToolbar.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
            self.bottomToolbar.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
            self.bottomToolbar.heightAnchor.constraint(equalToConstant: 44 + bottom),
            self.bottomToolbar.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
            ])

        self.mastImage.setContentHuggingPriority(.defaultHigh, for: .vertical)
        self.mastImage.setContentHuggingPriority(.defaultHigh, for: .horizontal)

        self.mastImage.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        self.mastImage.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        self.titleLbl.setContentCompressionResistancePriority(.required, for: .vertical)
        self.descriptionLbl.setContentCompressionResistancePriority(.required, for: .vertical)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension UIColor {
    class var random: UIColor {
        return UIColor(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1), alpha: 1.0)
    }
}

0 ответов

Другие вопросы по тегам