I want to make my viewController to dismiss to an old viewController with animation. But when I use CATransition my viewController and old viewController fades black. Is there any way I can make it not to fade?
let transition = CATransition()
transition.duration = 1.0
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
view.window!.layer.add(transition, forKey: kCATransition)
self.dismiss(animated: false, completion: nil)
Read more about transition here and try to modify available parameters to achieve required effects.
Good undocumented info about transition available here.
In case you want some good solution - you should prepare custom transition for your screen - check this WWDC video
Alternative fast (but not the best) solution may be manual control of presentation/dismiss in your viewController:
import UIKit
final class AnimatableViewController: UIViewController {
private var panStartLocation:CGPoint = CGPoint.zero
private var panPrevLocation:CGPoint = CGPoint.zero
var onClose:(()->())?
// MARK: - LifeCycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
openAnimation()
}
// MARK: - IBAction
@objc private func closeButtonAction(_ sender: UIButton) {
dismiss(animated: true, completion: { [weak self] in
self?.onClose?()
})
}
// MARK: - Gestures
@IBAction private func didDetectPan(_ sender: UIPanGestureRecognizer) {
switch sender.state {
case .began:
panStartLocation = sender.location(in: navigationController?.view)
panPrevLocation = panStartLocation
case .cancelled, .ended:
finishAnimation()
case .changed:
let newPoint:CGPoint = sender.location(in: navigationController?.view)
let dy:CGFloat = newPoint.y - panPrevLocation.y
var newPosition:CGPoint = view.center
if (newPoint.y - panStartLocation.y > 0) {
newPosition.y += dy
} else {
newPosition.y = self.view.bounds.height / 2
}
view.center = newPosition
panPrevLocation = newPoint
default:
break
}
}
//MARK: Animation
private func finishAnimation() {
let center:CGPoint = view.center
if (center.y > self.view.bounds.height / 2 * 1.35) {
closeAnimation()
} else {
openAnimation()
}
}
private func closeAnimation() {
let fullAnimTime:CGFloat = 0.5
let endPoint:CGPoint = CGPoint(x:view.center.x, y:view.bounds.height / 2 * 3)
let animTime:CGFloat = ((endPoint.y - view.center.y) / self.view.bounds.height) * fullAnimTime
UIView.animate(withDuration: TimeInterval(animTime), animations: { [weak self] in
self?.view.center = endPoint
}, completion: { [weak self] _ in
self?.dismiss(animated: false, completion: {
self?.onClose?()
})
})
}
private func openAnimation() {
let fullAnimTime:CGFloat = 0.5
let endPoint:CGPoint = CGPoint(x: view.center.x, y:self.view.bounds.height / 2)
let animTime:CGFloat = ((view.center.y - endPoint.y) / (self.view.bounds.height / 2)) * fullAnimTime
UIView.animate(withDuration: TimeInterval(animTime)) { [weak self] in
self?.view.center = endPoint
}
}
}
extension AnimatableViewController: UIGestureRecognizerDelegate {
// MARK: - UIGestureRecognizerDelegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
return false
}
return true
}
}
In storyboard don't forget to set you segue parameters as:
And add panGesture to your root view or any additional pan Gesture to top most view, that can be used for pan - in my case - i just add pan to rootView:
Result: