Created
November 30, 2016 11:47
-
-
Save skoirala/19b4cbec602548cee23bf6ae9e3ab414 to your computer and use it in GitHub Desktop.
Paging viewcontroller using interactive transitioning
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
extension UIColor { | |
static func randomColor() -> UIColor { | |
let red = CGFloat(arc4random_uniform(255)) / 255.0 | |
let green = CGFloat(arc4random_uniform(255)) / 255.0 | |
let blue = CGFloat(arc4random_uniform(255)) / 255.0 | |
return UIColor(red: red, green: green, blue: blue, alpha: 1.0) | |
} | |
} | |
class ViewController: UIViewController, UIViewControllerTransitioningDelegate { | |
var interactionController: InteractionController? | |
var gestureRecognizer: UIPanGestureRecognizer? | |
var slidesRight = true | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = UIColor.randomColor() | |
let panGestureRecognizer = UIPanGestureRecognizer(target: self, | |
action: #selector(panned)) | |
view.addGestureRecognizer(panGestureRecognizer) | |
self.gestureRecognizer = panGestureRecognizer | |
let tap = UITapGestureRecognizer(target: self, action: #selector(tapped)) | |
view.addGestureRecognizer(tap) | |
} | |
@objc | |
func tapped(tapGestureRecognizer: UITapGestureRecognizer) { | |
let viewController = ViewController() | |
viewController.transitioningDelegate = self | |
present(viewController, animated: true, completion: nil) | |
} | |
@objc | |
func panned(panGestureRecognizer: UIPanGestureRecognizer) { | |
switch panGestureRecognizer.state { | |
case .began: | |
let translation = panGestureRecognizer.translation(in: view) | |
if fabs(translation.x) > 0 { | |
if translation.x == 0 { | |
return; | |
} | |
if translation.x < 0 { | |
slidesRight = true | |
let viewController = ViewController() | |
viewController.transitioningDelegate = self | |
present(viewController, animated: true, completion: nil) | |
} else { | |
slidesRight = false | |
let viewController = ViewController() | |
viewController.transitioningDelegate = self | |
present(viewController, animated: true, completion: nil) | |
} | |
} | |
default: | |
print("Not presenting") | |
} | |
} | |
public func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { | |
self.interactionController = InteractionController(gestureRecognizer: gestureRecognizer!) | |
return self.interactionController! | |
} | |
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { | |
let slideDirection: SlideDirection = slidesRight ? .Right : .Left | |
return AnimationController(slideDirection: slideDirection) | |
} | |
} | |
class InteractionController: UIPercentDrivenInteractiveTransition { | |
let gestureRecognizer: UIPanGestureRecognizer | |
init(gestureRecognizer: UIPanGestureRecognizer) { | |
self.gestureRecognizer = gestureRecognizer | |
super.init() | |
self.gestureRecognizer.addTarget(self, action: #selector(panned)) | |
} | |
override var completionSpeed: CGFloat { | |
get { | |
return 1.0 - self.percentComplete | |
} | |
set {} | |
} | |
@objc | |
func panned(pan: UIPanGestureRecognizer) { | |
switch pan.state { | |
case .changed: | |
let translation = gestureRecognizer.translation(in: gestureRecognizer.view!) | |
let ratio = (translation.x / gestureRecognizer.view!.bounds.size.width) | |
update(abs(ratio)) | |
case .ended: | |
let translation = gestureRecognizer.translation(in: gestureRecognizer.view!) | |
let ratio = translation.x / gestureRecognizer.view!.bounds.size.width | |
if abs(ratio) > 0.30 { | |
finish() | |
} else { | |
cancel() | |
} | |
default: | |
print("Unrecognized state") | |
} | |
} | |
override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) { | |
super.startInteractiveTransition(transitionContext) | |
print("starting interactive transition") | |
} | |
} | |
enum SlideDirection { | |
case Left | |
case Right | |
} | |
class AnimationController: NSObject, UIViewControllerAnimatedTransitioning { | |
let slideDirection: SlideDirection | |
init(slideDirection: SlideDirection) { | |
self.slideDirection = slideDirection | |
} | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { | |
return 0.33 | |
} | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
let containerView = transitionContext.containerView | |
let toView = transitionContext.view(forKey: .to) | |
let fromView = transitionContext.view(forKey: .from) | |
toView?.frame = containerView.bounds | |
fromView?.frame = containerView.bounds | |
var translationX: CGFloat = 0 | |
if slideDirection == .Right { | |
translationX = containerView.bounds.size.width | |
} else { | |
translationX = -containerView.bounds.size.width | |
} | |
toView?.transform = CGAffineTransform(translationX: translationX, y: 0) | |
fromView?.transform = CGAffineTransform.identity | |
containerView.addSubview(toView!) | |
UIView.animate(withDuration: 0.33, delay: 0, options: .curveEaseInOut, animations: { | |
toView?.transform = CGAffineTransform.identity | |
fromView?.transform = CGAffineTransform(translationX: -translationX, y: 0) | |
}) { completed in | |
if transitionContext.transitionWasCancelled { | |
transitionContext.completeTransition(false) | |
fromView?.transform = CGAffineTransform.identity | |
} else { | |
transitionContext.completeTransition(true) | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment