Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@shial4
Last active September 28, 2018 02:29
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 shial4/4e5bfb5fb90f5e784cb3953e15c73edb to your computer and use it in GitHub Desktop.
Save shial4/4e5bfb5fb90f5e784cb3953e15c73edb to your computer and use it in GitHub Desktop.
Simple yet elegant push transition from the rect and back to the same rect.
//
// PushFromItemAnimator.swift
// Between
//
// Created by Shial on 11/9/18.
// Copyright © 2018 Szymon Lorenz Solutions. All rights reserved.
//
import UIKit
class PushFromItemAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var duration: TimeInterval
var isPresenting: Bool
var rect: CGRect?
init(duration: TimeInterval, rect: CGRect?, isPresenting: Bool) {
self.isPresenting = isPresenting
self.duration = duration
self.rect = rect
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
guard let fromView = transitionContext.view(forKey: .from) else {
transitionContext.completeTransition(false)
return
}
guard let toView = transitionContext.view(forKey: .to) else {
transitionContext.completeTransition(false)
return
}
let tabBar = transitionContext.viewController(forKey: .to)?.tabBarController?.tabBar
let tabBarHeight = tabBar?.frame.height ?? 0
let tabBarWidth = tabBar?.frame.width ?? 0
if self.isPresenting {
container.addSubview(toView)
toView.transform = transform(from: toView,
to: (self.rect ?? container.bounds).offsetBy(dx: 0, dy: tabBarHeight),
in: container)
tabBar?.transform = .identity
} else {
container.insertSubview(toView, belowSubview: fromView)
tabBar?.transform = CGAffineTransform(translationX: tabBarWidth, y: tabBarHeight)
}
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
if self.isPresenting {
tabBar?.transform = CGAffineTransform(translationX: tabBarWidth, y: tabBarHeight)
toView.transform = .identity
} else {
tabBar?.transform = .identity
fromView.transform = self.transform(from: fromView,
to: (self.rect ?? container.bounds).offsetBy(dx: 0, dy: tabBarHeight),
in: container)
fromView.alpha = 0
}
}) { finished in
tabBar?.transform = .identity
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func transform(from source: UIView, to destination: CGRect, in view: UIView) -> CGAffineTransform {
let destinationRect = view.convert(destination, to: view)
let sourceRect = source.convert(source.frame, to: view)
return CGAffineTransform.identity
.translatedBy(x: destinationRect.midX - sourceRect.midX, y: destinationRect.midY - sourceRect.midY)
.scaledBy(x: destination.width / source.frame.width, y: destination.height / source.frame.height)
}
}
extension YourPushedViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
switch operation {
case .push:
return PushFromItemAnimator(duration: TimeInterval(0.35), rect: rect, isPresenting: true)
default:
return PushFromItemAnimator(duration: TimeInterval(UINavigationControllerHideShowBarDuration), rect: rect, isPresenting: false)
}
}
}
@shial4
Copy link
Author

shial4 commented Sep 17, 2018

Custom push animation

Simple yet elegant push transition from the rect and back to the same rect.

Important

Remember to assign UINavigationControllerDelegate to YourPushedViewController so it can use custom transition coordinator.

Example

Example.gif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment