Created
September 15, 2024 23:12
-
-
Save nathantannar4/b45d10a683b043d7791e30bed5d6033d to your computer and use it in GitHub Desktop.
Custom PresentationLinkTransition
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 | |
import SwiftUI | |
import Transmission | |
extension PresentationLinkTransition { | |
static let custom: PresentationLinkTransition = .custom( | |
options: .init(), | |
CustomTransition() | |
) | |
} | |
struct CustomTransition: PresentationLinkTransitionRepresentable { | |
func makeUIPresentationController( | |
presented: UIViewController, | |
presenting: UIViewController?, | |
context: Context | |
) -> UIPresentationController { | |
let presentationController = UISheetPresentationController( | |
presentedViewController: presented, | |
presenting: presenting | |
) | |
presented.view.layer.cornerRadius = 14 | |
return presentationController | |
} | |
func updateUIPresentationController( | |
presentationController: UIPresentationController, | |
context: Context | |
) { | |
} | |
func animationController( | |
forPresented presented: UIViewController, | |
presenting: UIViewController, | |
context: Context | |
) -> UIViewControllerAnimatedTransitioning? { | |
MatchedGeometryTransition( | |
sourceView: context.sourceView, | |
isPresenting: true, | |
animation: nil | |
) | |
} | |
func animationController( | |
forDismissed dismissed: UIViewController, | |
context: Context | |
) -> UIViewControllerAnimatedTransitioning? { | |
MatchedGeometryTransition( | |
sourceView: context.sourceView, | |
isPresenting: false, | |
animation: nil | |
) | |
} | |
} | |
class MatchedGeometryTransition: PresentationControllerTransition { | |
weak var sourceView: UIView? | |
init( | |
sourceView: UIView, | |
isPresenting: Bool, | |
animation: Animation? | |
) { | |
super.init(isPresenting: isPresenting, animation: animation) | |
self.sourceView = sourceView | |
} | |
override func transitionAnimator( | |
using transitionContext: UIViewControllerContextTransitioning | |
) -> UIViewPropertyAnimator { | |
let animator = UIViewPropertyAnimator(animation: animation) ?? UIViewPropertyAnimator(duration: duration, curve: completionCurve) | |
guard | |
let presented = transitionContext.viewController(forKey: isPresenting ? .to : .from) | |
else { | |
transitionContext.completeTransition(false) | |
return animator | |
} | |
let isPresenting = isPresenting | |
let hostingController = presented as? AnyHostingController | |
let oldValue = hostingController?.disableSafeArea ?? false | |
hostingController?.disableSafeArea = true | |
var sourceFrame = sourceView.map { | |
$0.convert($0.frame, to: transitionContext.containerView) | |
} ?? transitionContext.containerView.frame | |
let presentedFrame = isPresenting | |
? transitionContext.finalFrame(for: presented) | |
: transitionContext.initialFrame(for: presented) | |
if isPresenting { | |
transitionContext.containerView.addSubview(presented.view) | |
presented.view.frame = sourceFrame | |
presented.view.layoutIfNeeded() | |
hostingController?.render() | |
} | |
animator.addAnimations { | |
if isPresenting { | |
hostingController?.disableSafeArea = oldValue | |
} | |
presented.view.frame = isPresenting ? presentedFrame : sourceFrame | |
presented.view.layoutIfNeeded() | |
} | |
animator.addCompletion { animatingPosition in | |
hostingController?.disableSafeArea = oldValue | |
switch animatingPosition { | |
case .end: | |
transitionContext.completeTransition(true) | |
default: | |
transitionContext.completeTransition(false) | |
} | |
} | |
return animator | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment