How to Animate Collection View Cells Using Hero Animation

How to Animate collection view cells using Hero Animation?

This is code for animation collection view cells like a closing door.
This collection has 2 columns.
I have added code for UICollectionViewDelegateFlowLayout methods for collection view cell sizes.
You can customize it or change it as per your requirement.

Sample Image

This code shows a simple way to generate animation like a closing door.

    // MARK: - UICollectionViewDelegateFlowLayout
extension SettingsViewController: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:CGFloat(settingsCollectionView.frame.size.width * 0.46), height: settingsCollectionView.frame.size.height * 0.25)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

// create a new cell if needed or reuse an old one
let cell: SettingsCollectionCell = settingsCollectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! SettingsCollectionCell

if !cell.isAnimated {

UIView.animate(withDuration: 0.5, delay: 0.5 * Double(indexPath.row), usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: indexPath.row % 2 == 0 ? .transitionFlipFromLeft : .transitionFlipFromRight, animations: {

if indexPath.row % 2 == 0 {
AnimationUtility.viewSlideInFromLeft(toRight: cell)
}
else {
AnimationUtility.viewSlideInFromRight(toLeft: cell)
}

}, completion: { (done) in
cell.isAnimated = true
})
}

return cell
}
}

This is code for AnimationUtility class.

class AnimationUtility: UIViewController, CAAnimationDelegate {

static let kSlideAnimationDuration: CFTimeInterval = 0.4

static func viewSlideInFromRight(toLeft views: UIView) {
var transition: CATransition? = nil
transition = CATransition.init()
transition?.duration = kSlideAnimationDuration
transition?.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition?.type = kCATransitionPush
transition?.subtype = kCATransitionFromRight
// transition?.delegate = (self as! CAAnimationDelegate)
views.layer.add(transition!, forKey: nil)
}

static func viewSlideInFromLeft(toRight views: UIView) {
var transition: CATransition? = nil
transition = CATransition.init()
transition?.duration = kSlideAnimationDuration
transition?.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition?.type = kCATransitionPush
transition?.subtype = kCATransitionFromLeft
// transition?.delegate = (self as! CAAnimationDelegate)
views.layer.add(transition!, forKey: nil)
}

static func viewSlideInFromTop(toBottom views: UIView) {
var transition: CATransition? = nil
transition = CATransition.init()
transition?.duration = kSlideAnimationDuration
transition?.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition?.type = kCATransitionPush
transition?.subtype = kCATransitionFromBottom
// transition?.delegate = (self as! CAAnimationDelegate)
views.layer.add(transition!, forKey: nil)
}

static func viewSlideInFromBottom(toTop views: UIView) {
var transition: CATransition? = nil
transition = CATransition.init()
transition?.duration = kSlideAnimationDuration
transition?.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition?.type = kCATransitionPush
transition?.subtype = kCATransitionFromTop
// transition?.delegate = (self as! CAAnimationDelegate)
views.layer.add(transition!, forKey: nil)
}
}

Hero ViewController animation with collectionView - swift

I think you must clear this heroID when cell is reused and after VC is presented.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
cell.heroID = nil // or empty
}

UIImageView animation inside UICollectionViewCell doesn't work

Both the collectionView(_:willDisplay:forItemAt:) method and the collectionView(_:cellForItemAt:) method are called before your cell is added to the view hierarchy. You can't trigger animation of a view until it is part of the view hierarchy.

I suggest adding the animation "smarts" to your UICollectionViewCell subclass (or to a content view that you put inside the collection view cell.

Have your collectionView(_:cellForItemAt:) set an "animationPending" property on your cell to true.

Then have your UICollectionViewCell respond to a didMoveToSuperview() call by checking it's "animationPending" flag. If it's true, run your animation code and set the flag back to false.

Push ViewController inside View that was presented with hero animation

You need to present communityVC after embedding the UINavigationController, then you can push the view controller inside communityVC, so you can push ViewController by using navigationController?.pushViewController(vc, animated: true) from communityV

    let communityVC = self.storyboard?.instantiateViewController(withIdentifier: "CommunityVC") as! CommunityViewController
let navController = UINavigationController(rootViewController: communityVC)
communityVC.hero.modalAnimationType = .zoomSlide(direction: .right)
let addButtonHeroID = "addWishButtonID"
self.addButton.heroID = addButtonHeroID
communityVC.homeButton.heroID = addButtonHeroID
self.present(navController, animated: true, completion: nil)

Table view cell load animation one after another

In your tableview delegate,

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

Put this bottom-to-top fade-in translation animation (Simplified from Anbu.Karthik answer),

    //1. Define the initial state (Before the animation)
cell.transform = CGAffineTransformMakeTranslation(0.f, CELL_HEIGHT);
cell.layer.shadowColor = [[UIColor blackColor]CGColor];
cell.layer.shadowOffset = CGSizeMake(10, 10);
cell.alpha = 0;

//2. Define the final state (After the animation) and commit the animation
[UIView beginAnimations:@"rotation" context:NULL];
[UIView setAnimationDuration:0.5];
cell.transform = CGAffineTransformMakeTranslation(0.f, 0);
cell.alpha = 1;
cell.layer.shadowOffset = CGSizeMake(0, 0);
[UIView commitAnimations];

For better UX, it is advised that the animation should only be played once for each row, until the table view is dealloc-ed.

Put the above code in

if (![self.shownIndexes containsObject:indexPath]) {
[self.shownIndexes addObject:indexPath];

// Your animation code here.
}

------- Swift -----------------------------------------------------------------------------------------------------------------

var shownIndexes : [IndexPath] = []
let CELL_HEIGHT : CGFloat = 40

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if (shownIndexes.contains(indexPath) == false) {
shownIndexes.append(indexPath)

cell.transform = CGAffineTransform(translationX: 0, y: CELL_HEIGHT)
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 10, height: 10)
cell.alpha = 0

UIView.beginAnimations("rotation", context: nil)
UIView.setAnimationDuration(0.5)
cell.transform = CGAffineTransform(translationX: 0, y: 0)
cell.alpha = 1
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
UIView.commitAnimations()
}
}


Related Topics



Leave a reply



Submit