Reputation: 841
I would like to animate all of my collectionview cells and this simplified example illustrates the problem. The problem is that if I scroll down while animating cells the ones that are not visible gets animated with a delay. I would like invisible cells to just be in the final state of animation instead of having animation delay.
In the video you see that when I scroll to the bottom, the final cells starts to animate with delay.
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var collectionview: UICollectionView!
var moveText: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
collectionview = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionview.translatesAutoresizingMaskIntoConstraints = false
collectionview.dataSource = self
collectionview.delegate = self
collectionview.backgroundColor = .systemBackground
collectionview.register(MyCell.self, forCellWithReuseIdentifier: "cell")
view.addSubview(collectionview)
NSLayoutConstraint.activate([
collectionview.topAnchor.constraint(equalTo: view.topAnchor),
collectionview.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionview.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionview.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
UIView.animate(withDuration: 1, delay: 0, options: [
UIView.AnimationOptions.allowAnimatedContent,
UIView.AnimationOptions.allowUserInteraction,
]) {
cell.moveText = self.moveText
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: collectionview.frame.width, height: 120)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { timer in
print("Starting animatings")
self.moveText.toggle()
self.collectionview.reloadData()
}
}
}
class MyCell: UICollectionViewCell {
let label = UILabel()
var moveText: Bool = false {
didSet {
if moveText == true {
label.transform = CGAffineTransform(translationX: 50, y: 50)
} else {
label.transform = .identity
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
label.text = "mytext"
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: leadingAnchor),
label.topAnchor.constraint(equalTo: topAnchor)
])
backgroundColor = .orange
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Upvotes: 0
Views: 145
Reputation: 4259
instead of animating inside the cellForItemAt
add this helper function.
private func animateVisibleCells() {
collectionview.visibleCells.compactMap { $0 as? MyCell }.forEach { cell in
UIView.animate(withDuration: 1, delay: 0, options: [
UIView.AnimationOptions.allowAnimatedContent,
UIView.AnimationOptions.allowUserInteraction,
]) {
cell.moveText = self.moveText
}
}
}
Now call it instead of reloading the collection view
Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { timer in
print("Starting animatings")
self.moveText.toggle()
self.animateVisibleCells()
}
and convert the cellForItemAt
implementation to:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
cell.moveText = moveText
return cell
}
Upvotes: 1