Skip to content

Instantly share code, notes, and snippets.

@nathantannar4
Created September 15, 2024 23:12
Show Gist options
  • Save nathantannar4/b45d10a683b043d7791e30bed5d6033d to your computer and use it in GitHub Desktop.
Save nathantannar4/b45d10a683b043d7791e30bed5d6033d to your computer and use it in GitHub Desktop.
Custom PresentationLinkTransition
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