Last active
August 11, 2024 09:48
-
-
Save alfian0/2a9fde9387cccf8cb298ad6caf2b04b9 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 UIKit | |
class PresentationController: UIPresentationController { | |
private var chrome: UIView = UIView() | |
var interactor: Interactor? = nil | |
override var frameOfPresentedViewInContainerView: CGRect { | |
guard let containerView = containerView, | |
let presentedView = presentedView else { return .zero } | |
let inset: CGFloat = 0 | |
var safeAreaFrame: CGRect = .zero | |
// Make sure to account for the safe area insets | |
if #available(iOS 11.0, *) { | |
safeAreaFrame = containerView.bounds | |
.inset(by: containerView.safeAreaInsets) | |
} else { | |
safeAreaFrame = containerView.bounds | |
} | |
let targetWidth = safeAreaFrame.width - (2 * inset) | |
let fittingSize = CGSize( | |
width: targetWidth, | |
height: UIView.layoutFittingCompressedSize.height | |
) | |
let targetHeight = presentedView.systemLayoutSizeFitting( | |
fittingSize, withHorizontalFittingPriority: .required, | |
verticalFittingPriority: .defaultLow).height | |
var frame = safeAreaFrame | |
frame.origin.x += inset | |
frame.origin.y += UIScreen.main.bounds.height - targetHeight - inset | |
frame.size.width = targetWidth | |
frame.size.height = targetHeight | |
return frame | |
} | |
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { | |
super.init(presentedViewController: presentedViewController, presenting: presentingViewController) | |
chrome.backgroundColor = UIColor(white: 0.0, alpha: 0.5) | |
chrome.alpha = 0.0 | |
chrome.addGestureRecognizer( | |
UITapGestureRecognizer(target: self, action: #selector(tapGesture(sender:))) | |
) | |
presentedViewController.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panGesture(_:)))) | |
} | |
@objc | |
private func panGesture(_ sender: UIPanGestureRecognizer) { | |
let percentThreshold: CGFloat = 0.3 | |
let translation = sender.translation(in: sender.view) | |
let verticalMovement = translation.y / sender.view!.bounds.height | |
let downwardMovement = fmaxf(Float(verticalMovement), 0.0) | |
let downwardMovementPercent = fminf(downwardMovement, 1.0) | |
let progress = CGFloat(downwardMovementPercent) | |
guard let interactor = interactor else { return } | |
switch sender.state { | |
case .began: | |
presentingViewController.dismiss(animated: true, completion: nil) | |
case .changed: | |
interactor.shouldFinish = progress > percentThreshold | |
interactor.update(progress) | |
case .cancelled: | |
interactor.hasStarted = false | |
interactor.cancel() | |
case .ended: | |
interactor.hasStarted = false | |
interactor.shouldFinish ? interactor.finish() : interactor.cancel() | |
default: | |
break | |
} | |
} | |
override func containerViewWillLayoutSubviews() { | |
chrome.frame = containerView!.bounds | |
presentedView?.center = .zero | |
presentedView?.roundCorners([.topLeft, .topRight], radius: 21) | |
presentedView?.frame = frameOfPresentedViewInContainerView | |
} | |
override func presentationTransitionWillBegin() { | |
containerView?.insertSubview(chrome, at: 0) | |
presentedViewController | |
.transitionCoordinator? | |
.animate(alongsideTransition: { (_) in | |
self.chrome.alpha = 1.0 | |
}, completion: nil) | |
} | |
override func dismissalTransitionWillBegin() { | |
presentedViewController | |
.transitionCoordinator? | |
.animate(alongsideTransition: { (_) in | |
self.chrome.alpha = 0.0 | |
}, completion: nil) | |
} | |
override func dismissalTransitionDidEnd(_ completed: Bool) { | |
if completed { | |
chrome.removeFromSuperview() | |
} | |
} | |
@objc private func tapGesture(sender: UIGestureRecognizer) { | |
presentedViewController.dismiss(animated: true, completion: nil) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment