I want to achieve the effect like this: I click cell and the button's alpha become to 0, then enlarge the cell and move to center of Screen.
And Here is my code and gif:
**// This is my VC**
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
private lazy var collectionView: UICollectionView = {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .vertical
flowLayout.itemSize = CGSize(width: 152, height: 212)
flowLayout.sectionInset = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
flowLayout.minimumLineSpacing = 24
flowLayout.minimumInteritemSpacing = 16
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
collectionView.register(ListViewControllerCell.self, forCellWithReuseIdentifier: "ListCell")
collectionView.dataSource = self
collectionView.delegate = self
collectionView.decelerationRate = .fast
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.clipsToBounds = false
collectionView.alwaysBounceVertical = true
return collectionView
}()
}
extension ViewController {
private func setupUI() {
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCell", for: indexPath)
return cell
}
}
class ListViewControllerCell: UICollectionViewCell {
static let identifier = "ListCell"
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
}
private lazy var pannelView: UIView = {
let view = UIView()
view.layer.cornerRadius = 8
view.backgroundColor = .yellow
return view
}()
private lazy var clickButton: UIButton = {
let button = UIButton()
button.layer.cornerRadius = 11
button.contentEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 8)
button.setTitle("Click Me!!", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.backgroundColor = .white
button.addTarget(self, action: #selector(onClickButton), for: .touchUpInside)
return button
}()
private func setupUI() {
contentView.addSubview(pannelView)
contentView.addSubview(clickButton)
pannelView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
clickButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().inset(16)
make.height.equalTo(22)
}
}
}
extension ListViewControllerCell {
@objc private func onClickButton() {
// 1: set button alpha to 0.
let buttonOpacity = CABasicAnimation(keyPath: "opacity")
buttonOpacity.toValue = 1
buttonOpacity.fromValue = 0
buttonOpacity.duration = 0.4
buttonOpacity.fillMode = .forwards
buttonOpacity.isRemovedOnCompletion = false
// 2: enlarge cell and set it position to center.
let cellEnlargeTransition = CABasicAnimation(keyPath: "transform.scale")
cellEnlargeTransition.fromValue = 1
cellEnlargeTransition.toValue = 2
cellEnlargeTransition.beginTime = CACurrentMediaTime() + 0.4
cellEnlargeTransition.duration = 1
cellEnlargeTransition.fillMode = .forwards
cellEnlargeTransition.isRemovedOnCompletion = false
let cellEnlargePosition = CAKeyframeAnimation(keyPath: "position")
let path = CGMutablePath()
path.move(to: CGPoint(x: contentView.frame.minX, y: contentView.frame.minY))
let toPositonX = (screenWidth - contentView.bounds.width)/2
let toPositionY = (screenWidth - contentView.bounds.height)/2
path.addLine(to: CGPoint(x: toPositonX, y: toPositionY))
cellEnlargePosition.path = path
cellEnlargePosition.beginTime = CACurrentMediaTime() + 0.4
cellEnlargeTransition.duration = 1
cellEnlargeTransition.fillMode = .forwards
cellEnlargePosition.isRemovedOnCompletion = false
CATransaction.begin()
clickButton.layer.add(buttonOpacity, forKey: nil)
contentView.layer.add(cellEnlargeTransition, forKey: nil)
contentView.layer.add(cellEnlargePosition, forKey: nil)
CATransaction.commit()
}
}
I have couple of questions:
1.
The beginning position is not right, the transition animation should start at cell's originX and originY.
2.
I want to keep button's alpha to zero, but it comes to 1 again when the "opacity" animation is over.
3.
The ending position is also not right, I want to keep it at center of the screen.
4.
I want the cell hierarchy to be higher than the others which do not execute animation.
The trouble (in addition to the fact that your whole approach to this animation is wrong) is that this is a collection view. To make a collection view cell actually appear in front of all the others, you would need to write a custom collection view layout — and you are not prepared to do that. And it wouldn't work in any case, because the whole collection view would still be scrollable, and then where would you be?
Instead, I suggest revising your design. Just use an interface like Apple's Photos app, or Calendar app. In Photos, for example, you see a grid of photos; you tap one and it zooms to fill the screen. That is actually a navigation view holding a view controller showing a collection view, pushed with a custom transition animation to a view controller holding the single photo, and is quite easy to do.
Alternatively I think you could quite readily do this as a collection view and a presented view controller with a transparent background showing the single "cell". The animation you see me doing here is quite analogous.