Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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