When using a UICollectionViewCell with animation triggered by a gesture recognizer, the animation stops abruptly when the array data associated with the collection view is reloaded using reloadData() method. The UICollectionViewCell contains a UILabel with an animation that scales the cell upon a long-press gesture. However, when reloadData() is called to update the data in the collection view, the animation of the UICollectionViewCell resets to its initial state, causing it to stop abruptly. This behavior disrupts the user experience and prevents the animation from completing smoothly as intended. The challenge is to find a solution that allows the animation to continue seamlessly even after the data is reloaded, ensuring a smooth and uninterrupted user interaction.
Horizontal Cell of UICollectionView:
final class HorizontalCell: UICollectionViewCell {
static let reuseIdentifier = "HorizontalCollectionViewCell"
private let numberLabel = UILabel()
private var originalTransform: CGAffineTransform?
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupGestureRecognizers()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
numberLabel.text = nil
}
private func setupViews() {
contentView.addSubview(numberLabel)
numberLabel.textAlignment = .center
numberLabel.layer.cornerRadius = 10
numberLabel.layer.borderWidth = 3
numberLabel.layer.borderColor = UIColor.lightGray.cgColor
numberLabel.backgroundColor = .white
numberLabel.textColor = .black
numberLabel.layer.masksToBounds = true
configure(with: item)
numberLabel.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(10)
}
}
var item: Int! = 0 {
didSet {
configure(with: item)
}
}
private func configure(with number: Int) {
numberLabel.text = "\(number)"
}
private func setupGestureRecognizers() {
let tapGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tapGesture.minimumPressDuration = 0
tapGesture.delegate = self
addGestureRecognizer(tapGesture)
}
@objc private func handleTap(_ gesture: UILongPressGestureRecognizer) {
switch gesture.state {
case .began:
DispatchQueue.global(qos: .userInteractive).async {
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 0.1
animation.fromValue = 1.0
animation.toValue = 0.8
animation.isRemovedOnCompletion = false
animation.fillMode = .forwards
CATransaction.begin()
CATransaction.setCompletionBlock {
self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
}
self.layer.add(animation, forKey: nil)
CATransaction.commit()
}
case .ended, .cancelled:
DispatchQueue.global(qos: .userInteractive).async {
let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 0.1
animation.fromValue = 0.8
animation.toValue = 1.0
animation.isRemovedOnCompletion = false
animation.fillMode = .forwards
CATransaction.begin()
CATransaction.setCompletionBlock {
self.transform = self.originalTransform ?? .identity
}
self.layer.add(animation, forKey: nil)
CATransaction.commit()
}
default:
break
}
}
}
extension HorizontalCell: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}
Timer starting method from Update Service class:
private func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateRandomNumber), userInfo: nil, repeats: true)
let runloop = RunLoop.main
runloop.add(timer!, forMode: .common)
}
@objc private func updateRandomNumber() {
for index in 0..<verticalItems.count {
var updatedHorizontalItems = verticalItems[index].horizontalItems
if let randomIndex = updatedHorizontalItems.indices.randomElement() {
updatedHorizontalItems[randomIndex] = Int.random(in: 1...100)
}
verticalItems[index].horizontalItems = updatedHorizontalItems
}
}
HorizontalCell is stored into UITableViewCell, which sets a new item for HorizontalCell and reloads a UICollectionView in didSet { }. UITableView reloads in UIViewController method when gets any changes from array in UpdateService.