Author | four niang, currently in long hui iOS group moved brick, Swift series language enthusiasts, delay in patients with advanced cancer. Source | the nuggets, can click on the “read” in the original view

The timing and effect of deselectRow in tableView is very special. Normally our deselect operation will be performed in the didSelect proxy method, or more specifically, in viewDidAppear.

But the iOS native App says no, I can do better, and here’s what it looks like in the system Settings:

The deselect animation will change with the progress of the sliding gesture when you slide back. After searching, there are not many articles about it in China, and the few software I use frequently do not have a similar effect.

Search after The record is rarely found abroad, only three articles to record The interaction, which more detailed written Diary # 17 – is this The Hit List are clearsSelectionOnViewWillAppear [1].

The abstract transitionCoordinator of transition animation

This interaction is achieved by UIViewController transitionCoordinator attributes, it is of type UIViewControllerTransitionCoordinator.

To put it simply, it can help us to add some custom animations into the transition animation. The progress and life cycle of the custom animation will be consistent with the transition animation, and it can achieve a more natural and consistent transition effect, such as the change of navigationBar background color in push animation. It provides these methods to register the callback of the animation life cycle:

protocol UIViewControllerTransitionCoordinator { func animate( alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)? , completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil ) -> Bool func animateAlongsideTransition( in view: UIView? , animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)? , completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil ) -> Bool func notifyWhenInteractionChanges( _ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void )}Copy the code

Recommend to see UIViewControllerTransitionCoordinator the agreement document [2], this excerpt a I think the more interesting description:

Using the transition coordinator to handle view hierarchy animations is preferred over making those same changes in the viewWillAppear(_:) or similar methods of your view controllers. The blocks you register with the methods of this protocol are guaranteed to execute at the same time as the transition animations. More importantly, the transition coordinator provides important information about the state of the transition, such as whether it was cancelled, to your animation blocks through the UIViewControllerTransitionCoordinatorContext object.

TransitionCoordinator is recommended to handle view-level animations rather than viewWillAppear and other similar ViewController lifecycle functions. The function you register is guaranteed to be executed at the same time as the transition animation. And, more importantly, through transitionCoordinator UIViewControllerTransitionCoordinatorContext agreement to provide the state transitions of animation and other important information, such as whether the animation has been cancelled.

The first thing that comes to my mind is navigationBar. Properties such as barTintColor can be used to animate transitions more naturally using transitionCoordinator.

Implementation and encapsulation

After looking at other people’s articles and trying other centralization methods, I felt that the best time for transitionCoordinator access would be viewWillAppear. The logic would look something like this:

override func viewWillAppear(_ animated: Bool) {super. ViewWillAppear (animated) / / judge whether there is the selected Row if let selectedIndexPath = tableView. IndexPathForSelectedRow { // Check whether a transitionCoordinator exists. If let coordinator = transitionCoordinator { By the coordinator to register animation block coordinator. The animate (alongsideTransition: {_ in the self. The tableView. DeselectRow (at: selectedIndexPath, animated: true) }, completion: {context in // If the transition animation is cancelled, Guard Context. isCancelled else {return} self.tableView.selectrow (at: SelectedIndexPath, animated: true, scrollPosition:.none)})} else {// Select tableView. DeselectRow (at: selectedIndexPath, animated: animated) } }}Copy the code

If the transitionCoordinator is simply an animation abstraction (leaving transitions behind), the operation we want to follow the animation through is deselect, We can further encapsulate the deselect operation into the UITableView extension:

extension UITableView { public func deselectRowIfNeeded(with transitionCoordinator: UIViewControllerTransitionCoordinator? , animated: Bool) { guard let selectedIndexPath = selectRowAtIndexPath else { return } guard let coordinator = transitionCoordinator  else { self.deselectRow(at: selectedIndexPath, animated: animated) return } coordinator.animate( alongsideTransition: { _ in self.deselectRow(at: selectedIndexPath, animated: true) }, completion: { context in guard context.isCancelled else { return } self.selectRow(at: selectedIndexPath, animated: false, scrollPosition: .none) } ) }}Copy the code

And then just call it in viewWillAppear:

override func viewWillAppear(_ animated: Bool) {    super.viewWillAppear(animated)    tableView.deselectRowIfNeeded(with: transitionCoordinator, animated: true)}Copy the code

If you package your Own TableViewController in your project and use it properly, it’s easy to add this effect.

conclusion

This is the complete example [3].

reference

[1]http://mikeabdullah.net/thl-diary-17-clearsselectiononviewwillappear.html [2]https://developer.apple.com/documentation/uikit/uiviewcontrollertransitioncoordinator  [3]https://github.com/kemchenj/DeselectRowTheBestWay [4]https://www.jianshu.com/p/6ec14f6762e5


When the child thread AutoRelease object is released
Swift5.0 Runtime
Mobile audio and video from zero to hand
YBImageBrowser refactoring Tips: How to optimize architecture, performance, and memory?
The internal implementation of the frame property in UIView