Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ricardopereira/a29f4594229277d6a79fe7ff48b8162a to your computer and use it in GitHub Desktop.
Save ricardopereira/a29f4594229277d6a79fe7ff48b8162a to your computer and use it in GitHub Desktop.
Animate table & collection view deselection alongside interactive transition (for iOS 11 and later)
Starting in iOS 11, interactive view controller transitions no longer scrub by setting the layer speed to zero
and changing the timeOffset. As a result of this change, implicit animations that occur in places like
-viewWillAppear: (called during an interactive transition) no longer end up “caught in” the animation.
To get the same behavior for table view row deselection as before, you can either use UITableViewController
which implements this for you, or you can implement it manually by deselecting the row in an alongside
animation for the transition (set up in -viewWillAppear: using the transition coordinator).
The example implementations here correctly handle some of the more subtle corner cases.
// UICollectionView Objective-C example
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSIndexPath *selectedIndexPath = [[self.collectionView indexPathsForSelectedItems] firstObject];
if (selectedIndexPath != nil) {
id<UIViewControllerTransitionCoordinator> coordinator = self.transitionCoordinator;
if (coordinator != nil) {
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.collectionView deselectItemAtIndexPath:selectedIndexPath animated:YES];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (context.cancelled) {
[self.collectionView selectItemAtIndexPath:selectedIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
}
}];
} else {
[self.collectionView deselectItemAtIndexPath:selectedIndexPath animated:animated];
}
}
}
// UICollectionView Swift example
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let indexPath = collectionView.indexPathsForSelectedItems?.first {
if let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: { _ in
self.collectionView.deselectItem(at: indexPath, animated: true)
}, completion: { context in
if context.isCancelled {
self.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])
}
})
} else {
collectionView.deselectItem(at: indexPath, animated: animated)
}
}
}
// UITableView Objective-C example
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
if (selectedIndexPath != nil) {
id<UIViewControllerTransitionCoordinator> coordinator = self.transitionCoordinator;
if (coordinator != nil) {
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
[self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (context.cancelled) {
[self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}];
} else {
[self.tableView deselectRowAtIndexPath:selectedIndexPath animated:animated];
}
}
}
// UITableView Swift example
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let selectedIndexPath = tableView.indexPathForSelectedRow {
if let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: { _ in
self.tableView.deselectRow(at: selectedIndexPath, animated: true)
}, completion: { context in
if context.isCancelled {
self.tableView.selectRow(at: selectedIndexPath, animated: false, scrollPosition: .none)
}
})
} else {
tableView.deselectRow(at: selectedIndexPath, animated: animated)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment