The additional toolbars to extend the edges beyond the navigation controller's bounds weren't positioned correctly on iOS 13.
201 lines
9.8 KiB
Swift
201 lines
9.8 KiB
Swift
//
|
|
// GamesStoryboardSegue.swift
|
|
// Delta
|
|
//
|
|
// Created by Riley Testut on 8/7/16.
|
|
// Copyright © 2016 Riley Testut. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
class GamesStoryboardSegue: UIStoryboardSegue
|
|
{
|
|
private let animator: UIViewPropertyAnimator
|
|
|
|
private var isPresenting: Bool = true
|
|
|
|
override init(identifier: String?, source: UIViewController, destination: UIViewController)
|
|
{
|
|
let timingParameters = UISpringTimingParameters(mass: 3.0, stiffness: 750, damping: 65, initialVelocity: CGVector(dx: 0, dy: 0))
|
|
self.animator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParameters)
|
|
|
|
super.init(identifier: identifier, source: source, destination: destination)
|
|
}
|
|
|
|
override func perform()
|
|
{
|
|
self.destination.transitioningDelegate = self
|
|
self.destination.modalPresentationStyle = .custom
|
|
self.destination.modalPresentationCapturesStatusBarAppearance = true
|
|
|
|
super.perform()
|
|
}
|
|
}
|
|
|
|
extension GamesStoryboardSegue: UIViewControllerTransitioningDelegate
|
|
{
|
|
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
|
|
{
|
|
self.isPresenting = true
|
|
return self
|
|
}
|
|
|
|
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
|
|
{
|
|
self.isPresenting = false
|
|
return self
|
|
}
|
|
|
|
func presentationController(forPresented presentedViewController: UIViewController, presenting presentingViewController: UIViewController?, source: UIViewController) -> UIPresentationController?
|
|
{
|
|
let presentationController = GamesPresentationController(presentedViewController: presentedViewController, presenting: presentingViewController, animator: self.animator)
|
|
return presentationController
|
|
}
|
|
}
|
|
|
|
extension GamesStoryboardSegue: UIViewControllerAnimatedTransitioning
|
|
{
|
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
|
|
{
|
|
return self.animator.duration
|
|
}
|
|
|
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
|
|
{
|
|
if self.isPresenting
|
|
{
|
|
self.animatePresentationTransition(using: transitionContext)
|
|
}
|
|
else
|
|
{
|
|
self.animateDismissalTransition(using: transitionContext)
|
|
}
|
|
}
|
|
|
|
func animatePresentationTransition(using transitionContext: UIViewControllerContextTransitioning)
|
|
{
|
|
transitionContext.sourceViewController.beginAppearanceTransition(false, animated: true)
|
|
|
|
transitionContext.destinationView.clipsToBounds = false
|
|
transitionContext.destinationView.frame = transitionContext.destinationViewFinalFrame!
|
|
transitionContext.destinationView.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
|
|
transitionContext.containerView.addSubview(transitionContext.destinationView)
|
|
|
|
let snapshotView = transitionContext.sourceView.snapshotView(afterScreenUpdates: false)!
|
|
snapshotView.frame = transitionContext.sourceViewInitialFrame!
|
|
snapshotView.alpha = 1.0
|
|
transitionContext.containerView.addSubview(snapshotView)
|
|
|
|
// We add extra padding around the existing navigation bar and toolbar so they never appear to be detached from the edges of the screen during the overshooting of the spring animation
|
|
var topPaddingToolbar: UIToolbar? = nil
|
|
var bottomPaddingToolbar: UIToolbar? = nil
|
|
|
|
// Must be wrapped in no-animation block to prevent iOS 11 search bar from not appearing.
|
|
UIView.performWithoutAnimation {
|
|
// Ensures navigation controller toolbar (if visible) has been added to view heirachy, allowing us to add constraints
|
|
transitionContext.containerView.layoutIfNeeded()
|
|
|
|
if let navigationController = transitionContext.destinationViewController as? UINavigationController
|
|
{
|
|
let padding: CGFloat = 44
|
|
let topViewController = navigationController.viewControllers[0]
|
|
|
|
if !navigationController.isNavigationBarHidden
|
|
{
|
|
let topToolbar = UIToolbar(frame: CGRect.zero)
|
|
topToolbar.translatesAutoresizingMaskIntoConstraints = false
|
|
topToolbar.barStyle = navigationController.toolbar.barStyle
|
|
transitionContext.destinationView.insertSubview(topToolbar, at: 1)
|
|
|
|
if #available(iOS 13, *)
|
|
{
|
|
let appearance = UIToolbarAppearance(barAppearance: navigationController.navigationBar.standardAppearance)
|
|
topToolbar.standardAppearance = appearance
|
|
|
|
topToolbar.topAnchor.constraint(equalTo: topViewController.view.topAnchor, constant: -padding).isActive = true
|
|
topToolbar.leftAnchor.constraint(equalTo: topViewController.view.leftAnchor, constant: -padding).isActive = true
|
|
topToolbar.rightAnchor.constraint(equalTo: topViewController.view.rightAnchor, constant: padding).isActive = true
|
|
topToolbar.bottomAnchor.constraint(equalTo: topViewController.view.safeAreaLayoutGuide.topAnchor).isActive = true
|
|
}
|
|
else
|
|
{
|
|
topToolbar.topAnchor.constraint(equalTo: navigationController.navigationBar.topAnchor, constant: -padding).isActive = true
|
|
topToolbar.leftAnchor.constraint(equalTo: navigationController.navigationBar.leftAnchor, constant: -padding).isActive = true
|
|
topToolbar.rightAnchor.constraint(equalTo: navigationController.navigationBar.rightAnchor, constant: padding).isActive = true
|
|
|
|
// There is no easy way to determine the extra height necessary at this point of the transition, so hard code for now.
|
|
let additionalSearchBarHeight = 44 as CGFloat
|
|
topToolbar.heightAnchor.constraint(equalToConstant: navigationController.topViewController!.view.safeAreaInsets.top + additionalSearchBarHeight).isActive = true
|
|
}
|
|
|
|
topPaddingToolbar = topToolbar
|
|
}
|
|
|
|
if !navigationController.isToolbarHidden
|
|
{
|
|
let bottomToolbar = UIToolbar(frame: CGRect.zero)
|
|
bottomToolbar.translatesAutoresizingMaskIntoConstraints = false
|
|
bottomToolbar.barStyle = navigationController.toolbar.barStyle
|
|
transitionContext.destinationView.insertSubview(bottomToolbar, belowSubview: navigationController.navigationBar)
|
|
|
|
if #available(iOS 13, *)
|
|
{
|
|
let appearance = UIToolbarAppearance(barAppearance: navigationController.toolbar.standardAppearance)
|
|
bottomToolbar.standardAppearance = appearance
|
|
|
|
bottomToolbar.topAnchor.constraint(equalTo: topViewController.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
|
|
bottomToolbar.bottomAnchor.constraint(equalTo: topViewController.view.bottomAnchor, constant: padding).isActive = true
|
|
bottomToolbar.leftAnchor.constraint(equalTo: topViewController.view.leftAnchor, constant: -padding).isActive = true
|
|
bottomToolbar.rightAnchor.constraint(equalTo: topViewController.view.rightAnchor, constant: padding).isActive = true
|
|
}
|
|
else
|
|
{
|
|
bottomToolbar.topAnchor.constraint(equalTo: navigationController.toolbar.topAnchor).isActive = true
|
|
bottomToolbar.bottomAnchor.constraint(equalTo: navigationController.toolbar.bottomAnchor, constant: padding).isActive = true
|
|
bottomToolbar.leftAnchor.constraint(equalTo: navigationController.toolbar.leftAnchor, constant: -padding).isActive = true
|
|
bottomToolbar.rightAnchor.constraint(equalTo: navigationController.toolbar.rightAnchor, constant: padding).isActive = true
|
|
}
|
|
|
|
bottomPaddingToolbar = bottomToolbar
|
|
}
|
|
}
|
|
}
|
|
|
|
self.animator.addAnimations {
|
|
snapshotView.alpha = 0.0
|
|
transitionContext.destinationView.transform = CGAffineTransform.identity
|
|
}
|
|
|
|
self.animator.addCompletion { (position) in
|
|
transitionContext.completeTransition(position == .end)
|
|
|
|
snapshotView.removeFromSuperview()
|
|
|
|
topPaddingToolbar?.removeFromSuperview()
|
|
bottomPaddingToolbar?.removeFromSuperview()
|
|
|
|
transitionContext.sourceViewController.endAppearanceTransition()
|
|
}
|
|
|
|
self.animator.startAnimation()
|
|
}
|
|
|
|
func animateDismissalTransition(using transitionContext: UIViewControllerContextTransitioning)
|
|
{
|
|
transitionContext.destinationViewController.beginAppearanceTransition(true, animated: true)
|
|
|
|
self.animator.addAnimations {
|
|
transitionContext.sourceView.alpha = 0.0
|
|
transitionContext.sourceView.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
|
|
}
|
|
|
|
self.animator.addCompletion { (position) in
|
|
transitionContext.completeTransition(position == .end)
|
|
transitionContext.destinationViewController.endAppearanceTransition()
|
|
}
|
|
|
|
self.animator.startAnimation()
|
|
}
|
|
}
|
|
|