Last active
March 14, 2017 08:20
-
-
Save keisei1092/749406e16fe988ef4349d5a4294b596f to your computer and use it in GitHub Desktop.
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 XCPlayground | |
import UIKit | |
class ViewController: UIViewController { | |
var button: UIButton? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .white | |
setupButton() | |
} | |
func buttonTouchUpInside(_ sender: UIButton) { | |
let modalViewController = ModalViewController() | |
modalViewController.modalPresentationStyle = .custom | |
modalViewController.transitioningDelegate = self | |
modalViewController.view.backgroundColor = .green | |
present(modalViewController, animated: true, completion: nil) | |
} | |
private func setupButton() { | |
button = UIButton(frame: CGRect(x: 110, y: 190, width: 100, height: 100)) | |
button?.setTitle("ホゲ", for: .normal) | |
button?.backgroundColor = .red | |
button?.layer.cornerRadius = 4 | |
button?.addTarget(self, action: #selector(ViewController.buttonTouchUpInside(_:)), for: .touchUpInside) | |
view.addSubview(button!) | |
} | |
} | |
extension ViewController: UIViewControllerTransitioningDelegate { | |
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { | |
return CustomPresentationController(presentedViewController: presented, presenting: presenting) | |
} | |
} | |
extension ViewController { | |
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { | |
return CustomAnimatedTransitioning(isPresent: true, atButton: button) | |
} | |
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { | |
return CustomAnimatedTransitioning(isPresent: false, atButton: button) | |
} | |
} | |
class ModalViewController: UIViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
} | |
} | |
class CustomPresentationController: UIPresentationController { | |
var overlayView = UIView() | |
let modalHeight = CGFloat(132.0) | |
let margin = (x: CGFloat(60), y: CGFloat(0.0)) | |
override func presentationTransitionWillBegin() { | |
guard let containerView = containerView else { | |
return | |
} | |
overlayView.frame = containerView.bounds | |
overlayView.gestureRecognizers = [UITapGestureRecognizer(target: self, action: #selector(CustomPresentationController.overlayViewDidTouch(sender:)))] | |
overlayView.backgroundColor = .black | |
overlayView.alpha = 0.0 | |
containerView.insertSubview(overlayView, at: 0) | |
presentedViewController.transitionCoordinator?.animate(alongsideTransition: { [weak self] context in | |
self?.overlayView.alpha = 0.5 | |
}, completion: nil) | |
} | |
override func dismissalTransitionWillBegin() { | |
presentedViewController.transitionCoordinator?.animate(alongsideTransition: { [weak self] context in | |
self?.overlayView.alpha = 0.0 | |
}, completion: nil) | |
} | |
override func dismissalTransitionDidEnd(_ completed: Bool) { | |
if completed { | |
overlayView.removeFromSuperview() | |
} | |
} | |
override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize { | |
return CGSize(width: parentSize.width - margin.x, height: modalHeight) | |
} | |
override var frameOfPresentedViewInContainerView: CGRect { | |
var presentedViewFrame = CGRect.zero | |
let containerBounds = containerView!.bounds | |
let childContentSize = size(forChildContentContainer: presentedViewController, withParentContainerSize: containerBounds.size) | |
presentedViewFrame.size = childContentSize | |
presentedViewFrame.origin.x = margin.x / 2.0 | |
presentedViewFrame.origin.y = containerBounds.height / 2.0 - modalHeight / 2.0 | |
return presentedViewFrame | |
} | |
override func containerViewWillLayoutSubviews() { | |
overlayView.frame = containerView!.bounds | |
presentedView!.frame = frameOfPresentedViewInContainerView | |
} | |
override func containerViewDidLayoutSubviews() { | |
} | |
func overlayViewDidTouch(sender: AnyObject) { | |
presentedViewController.dismiss(animated: true, completion: nil) | |
} | |
} | |
class CustomAnimatedTransitioning: NSObject, UIViewControllerAnimatedTransitioning { | |
let isPresent: Bool | |
let atButton: UIButton | |
init(isPresent: Bool, atButton: UIButton?) { | |
self.isPresent = isPresent | |
self.atButton = atButton ?? UIButton(frame: CGRect.zero) | |
} | |
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { | |
return 1.0 | |
} | |
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
if isPresent { | |
animatePresentTransition(transitionContext: transitionContext) | |
} else { | |
animateDissmissalTransition(transitionContext: transitionContext) | |
} | |
} | |
func animatePresentTransition(transitionContext: UIViewControllerContextTransitioning) { | |
guard | |
let presentingController = transitionContext.viewController(forKey: .from), | |
let presentedController = transitionContext.viewController(forKey: .to) | |
else { | |
return | |
} | |
let containerView = transitionContext.containerView | |
presentedController.view.layer.cornerRadius = 4.0 | |
presentedController.view.clipsToBounds = true | |
presentedController.view.alpha = 0.0 | |
presentedController.view.transform = CGAffineTransform(scaleX: 0.01, y: 0.01) | |
DispatchQueue.main.async { | |
containerView.insertSubview(presentedController.view, belowSubview: presentingController.view) | |
} | |
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.6, options: .curveLinear, animations: { | |
presentedController.view.alpha = 1.0 | |
presentedController.view.frame.origin.x = containerView.bounds.size.width - self.atButton.frame.origin.x | |
presentedController.view.frame.origin.y = containerView.bounds.size.height - self.atButton.frame.origin.y | |
presentedController.view.transform = .identity | |
}, completion: { finished in | |
transitionContext.completeTransition(true) | |
}) | |
} | |
func animateDissmissalTransition(transitionContext: UIViewControllerContextTransitioning) { | |
guard let presentedController = transitionContext.viewController(forKey: .from) else { | |
return | |
} | |
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.6, options: .curveLinear, animations:{ | |
presentedController.view.alpha = 0.0 | |
presentedController.view.transform = CGAffineTransform(scaleX: 0.00, y: 0.00) | |
presentedController.view.frame.origin.x = self.atButton.frame.origin.x | |
presentedController.view.frame.origin.y = self.atButton.frame.origin.y | |
}, completion: { finished in | |
transitionContext.completeTransition(true) | |
}) | |
} | |
} | |
let rootViewController = ViewController() | |
rootViewController.title = "test" | |
let navigationController = UINavigationController(rootViewController: rootViewController) | |
navigationController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480) | |
XCPlaygroundPage.currentPage.liveView = navigationController.view |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment