Как добиться флип-анимации с помощью 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)
}
}