diff --git a/BottomPopup.xcodeproj/project.pbxproj b/BottomPopup.xcodeproj/project.pbxproj index 30a7ead..9d8d72e 100644 --- a/BottomPopup.xcodeproj/project.pbxproj +++ b/BottomPopup.xcodeproj/project.pbxproj @@ -329,7 +329,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = MYV44LEMW9; + DEVELOPMENT_TEAM = UR2UCZHHPB; INFOPLIST_FILE = BottomPopup/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -348,7 +348,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = MYV44LEMW9; + DEVELOPMENT_TEAM = UR2UCZHHPB; INFOPLIST_FILE = BottomPopup/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/BottomPopup/Base.lproj/Main.storyboard b/BottomPopup/Base.lproj/Main.storyboard index ee33d05..8c66f57 100644 --- a/BottomPopup/Base.lproj/Main.storyboard +++ b/BottomPopup/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -16,7 +16,7 @@ - - + @@ -39,13 +39,13 @@ @@ -63,13 +63,13 @@ @@ -87,13 +87,13 @@ @@ -111,13 +111,13 @@ @@ -129,19 +129,54 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -169,17 +205,18 @@ - + + @@ -197,13 +234,13 @@ - + @@ -220,7 +258,6 @@ - @@ -236,18 +273,18 @@ + - @@ -268,8 +305,8 @@ - + @@ -282,7 +319,7 @@ - + @@ -300,7 +337,7 @@ - + @@ -313,4 +350,9 @@ + + + + + diff --git a/BottomPopup/BottomPopupController/BottomPopupDismissAnimator.swift b/BottomPopup/BottomPopupController/BottomPopupDismissAnimator.swift index 4004c83..30c023c 100644 --- a/BottomPopup/BottomPopupController/BottomPopupDismissAnimator.swift +++ b/BottomPopup/BottomPopupController/BottomPopupDismissAnimator.swift @@ -21,7 +21,8 @@ final class BottomPopupDismissAnimator: NSObject, UIViewControllerAnimatedTransi func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let fromVC = transitionContext.viewController(forKey: .from)! - let dismissFrame = CGRect(origin: CGPoint(x: 0, y: UIScreen.main.bounds.size.height), size: fromVC.view.frame.size) + let x = attributesOwner.view.frame.origin.x + let dismissFrame = CGRect(origin: CGPoint(x: x, y: UIScreen.main.bounds.size.height), size: fromVC.view.frame.size) UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { fromVC.view.frame = dismissFrame diff --git a/BottomPopup/BottomPopupController/BottomPopupNavigationController.swift b/BottomPopup/BottomPopupController/BottomPopupNavigationController.swift index a8bddc7..ce63dda 100644 --- a/BottomPopup/BottomPopupController/BottomPopupNavigationController.swift +++ b/BottomPopup/BottomPopupController/BottomPopupNavigationController.swift @@ -9,6 +9,7 @@ import UIKit open class BottomPopupNavigationController: UINavigationController, BottomPopupAttributesDelegate { + private var transitionHandler: BottomPopupTransitionHandler? open weak var popupDelegate: BottomPopupDelegate? @@ -32,7 +33,12 @@ open class BottomPopupNavigationController: UINavigationController, BottomPopupA popupDelegate?.bottomPopupViewLoaded() self.view.accessibilityIdentifier = popupViewAccessibilityIdentifier } - + + open override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + curveTopCorners() + } + override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -76,6 +82,7 @@ open class BottomPopupNavigationController: UINavigationController, BottomPopupA // MARK: - BottomPopupAttributesDelegate Variables open var popupHeight: CGFloat { BottomPopupConstants.defaultHeight } + open var popupWidth: CGFloat { BottomPopupConstants.defaultWidth } open var popupTopCornerRadius: CGFloat { BottomPopupConstants.defaultTopCornerRadius } open var popupPresentDuration: Double { BottomPopupConstants.defaultPresentDuration } open var popupDismissDuration: Double { BottomPopupConstants.defaultDismissDuration } @@ -83,6 +90,8 @@ open class BottomPopupNavigationController: UINavigationController, BottomPopupA open var popupDimmingViewAlpha: CGFloat { BottomPopupConstants.dimmingViewDefaultAlphaValue } open var popupShouldBeganDismiss: Bool { BottomPopupConstants.shouldBeganDismiss } open var popupViewAccessibilityIdentifier: String { BottomPopupConstants.defaultPopupViewAccessibilityIdentifier } + open var popupShouldDismissOnTap: Bool { BottomPopupConstants.dismissOnTap } + } extension BottomPopupNavigationController { diff --git a/BottomPopup/BottomPopupController/BottomPopupPresentAnimator.swift b/BottomPopup/BottomPopupController/BottomPopupPresentAnimator.swift index 046fd22..e91c09d 100644 --- a/BottomPopup/BottomPopupController/BottomPopupPresentAnimator.swift +++ b/BottomPopup/BottomPopupController/BottomPopupPresentAnimator.swift @@ -23,7 +23,7 @@ final class BottomPopupPresentAnimator: NSObject, UIViewControllerAnimatedTransi let toVC = transitionContext.viewController(forKey: .to)! transitionContext.containerView.addSubview(toVC.view) let presentFrame = transitionContext.finalFrame(for: toVC) - let initialFrame = CGRect(origin: CGPoint(x: 0, y: UIScreen.main.bounds.size.height), size: presentFrame.size) + let initialFrame = CGRect(origin: CGPoint(x: presentFrame.origin.x, y: UIScreen.main.bounds.size.height), size: presentFrame.size) toVC.view.frame = initialFrame UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { toVC.view.frame = presentFrame diff --git a/BottomPopup/BottomPopupController/BottomPopupPresentationController.swift b/BottomPopup/BottomPopupController/BottomPopupPresentationController.swift index a1f94ad..3bda141 100644 --- a/BottomPopup/BottomPopupController/BottomPopupPresentationController.swift +++ b/BottomPopup/BottomPopupController/BottomPopupPresentationController.swift @@ -11,10 +11,13 @@ import UIKit final class BottomPopupPresentationController: UIPresentationController { private var dimmingView: UIView! private var popupHeight: CGFloat + private var popupWidth: CGFloat private unowned var attributesDelegate: BottomPopupAttributesDelegate override var frameOfPresentedViewInContainerView: CGRect { - CGRect(origin: CGPoint(x: 0, y: UIScreen.main.bounds.size.height - popupHeight), size: CGSize(width: presentedViewController.view.frame.size.width, height: popupHeight)) + let viewWidth = containerView?.frame.width ?? 0 + let x = (viewWidth - popupWidth) / 2 + return CGRect(origin: CGPoint(x: x, y: UIScreen.main.bounds.size.height - popupHeight), size: CGSize(width: popupWidth, height: popupHeight)) } private func changeDimmingViewAlphaAlongWithAnimation(to alpha: CGFloat) { @@ -31,16 +34,27 @@ final class BottomPopupPresentationController: UIPresentationController { init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?, attributesDelegate: BottomPopupAttributesDelegate) { self.attributesDelegate = attributesDelegate popupHeight = attributesDelegate.popupHeight + popupWidth = attributesDelegate.popupWidth super.init(presentedViewController: presentedViewController, presenting: presentingViewController) setupDimmingView() } - override func containerViewWillLayoutSubviews() { + override func containerViewDidLayoutSubviews() { + dimmingView.frame = containerView?.bounds ?? .zero presentedView?.frame = frameOfPresentedViewInContainerView } override func presentationTransitionWillBegin() { containerView?.insertSubview(dimmingView, at: 0) + if let containerView { + dimmingView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + dimmingView.topAnchor.constraint(equalTo: containerView.topAnchor), + dimmingView.leftAnchor.constraint(equalTo: containerView.leftAnchor), + dimmingView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + dimmingView.rightAnchor.constraint(equalTo: containerView.rightAnchor), + ]) + } changeDimmingViewAlphaAlongWithAnimation(to: attributesDelegate.popupDimmingViewAlpha) } @@ -57,11 +71,13 @@ final class BottomPopupPresentationController: UIPresentationController { @objc private func handleTap(_ tap: UITapGestureRecognizer) { guard attributesDelegate.popupShouldBeganDismiss else { return } + guard attributesDelegate.popupShouldDismissOnTap else { return } presentedViewController.dismiss(animated: true, completion: nil) } @objc private func handleSwipe(_ swipe: UISwipeGestureRecognizer) { guard attributesDelegate.popupShouldBeganDismiss else { return } + guard attributesDelegate.popupShouldDismissInteractivelty else { return } presentedViewController.dismiss(animated: true, completion: nil) } } diff --git a/BottomPopup/BottomPopupController/BottomPopupUtils.swift b/BottomPopup/BottomPopupController/BottomPopupUtils.swift index 92098f1..e20a50f 100644 --- a/BottomPopup/BottomPopupController/BottomPopupUtils.swift +++ b/BottomPopup/BottomPopupController/BottomPopupUtils.swift @@ -30,6 +30,7 @@ public extension BottomPopupDelegate { public protocol BottomPopupAttributesDelegate: class { var popupHeight: CGFloat { get } + var popupWidth: CGFloat { get } var popupTopCornerRadius: CGFloat { get } var popupPresentDuration: Double { get } var popupDismissDuration: Double { get } @@ -37,16 +38,19 @@ public protocol BottomPopupAttributesDelegate: class { var popupDimmingViewAlpha: CGFloat { get } var popupShouldBeganDismiss: Bool { get } var popupViewAccessibilityIdentifier: String { get } + var popupShouldDismissOnTap: Bool { get } } public enum BottomPopupConstants { static let minPercentOfVisiblePartToCompleteAnimation: CGFloat = 0.5 static let swipeDownThreshold: CGFloat = 1000 static let defaultHeight: CGFloat = 377.0 + static let defaultWidth: CGFloat = 377.0 static let defaultTopCornerRadius: CGFloat = 10.0 static let defaultPresentDuration = 0.5 static let defaultDismissDuration = 0.5 static let dismissInteractively = true + static let dismissOnTap = true static let shouldBeganDismiss = true static let dimmingViewDefaultAlphaValue: CGFloat = 0.5 static let defaultPopupViewAccessibilityIdentifier: String = "bottomPopupView" diff --git a/BottomPopup/BottomPopupController/BottomPopupViewController.swift b/BottomPopup/BottomPopupController/BottomPopupViewController.swift index b6cb92d..62d8f1c 100644 --- a/BottomPopup/BottomPopupController/BottomPopupViewController.swift +++ b/BottomPopup/BottomPopupController/BottomPopupViewController.swift @@ -30,7 +30,12 @@ open class BottomPopupViewController: UIViewController, BottomPopupAttributesDel popupDelegate?.bottomPopupViewLoaded() view.accessibilityIdentifier = popupViewAccessibilityIdentifier } - + + open override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + curveTopCorners() + } + open override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) curveTopCorners() @@ -74,6 +79,7 @@ open class BottomPopupViewController: UIViewController, BottomPopupAttributesDel // MARK: - BottomPopupAttributesDelegate Variables open var popupHeight: CGFloat { BottomPopupConstants.defaultHeight } + open var popupWidth: CGFloat { BottomPopupConstants.defaultWidth } open var popupTopCornerRadius: CGFloat { BottomPopupConstants.defaultTopCornerRadius } open var popupPresentDuration: Double { BottomPopupConstants.defaultPresentDuration } open var popupDismissDuration: Double { BottomPopupConstants.defaultDismissDuration } @@ -81,4 +87,6 @@ open class BottomPopupViewController: UIViewController, BottomPopupAttributesDel open var popupDimmingViewAlpha: CGFloat { BottomPopupConstants.dimmingViewDefaultAlphaValue } open var popupShouldBeganDismiss: Bool { BottomPopupConstants.shouldBeganDismiss } open var popupViewAccessibilityIdentifier: String { BottomPopupConstants.defaultPopupViewAccessibilityIdentifier } + open var popupShouldDismissOnTap: Bool { BottomPopupConstants.dismissOnTap } + } diff --git a/BottomPopup/ExampleNavigationController.swift b/BottomPopup/ExampleNavigationController.swift index 5d32a0d..a16eb0d 100644 --- a/BottomPopup/ExampleNavigationController.swift +++ b/BottomPopup/ExampleNavigationController.swift @@ -14,6 +14,8 @@ class ExampleNavigationController: BottomPopupNavigationController { var presentDuration: Double? var dismissDuration: Double? var shouldDismissInteractivelty: Bool? + var shouldBeganDismiss: Bool? + var shouldDismissOnTap: Bool? // MARK: - BottomPopupAttributesDelegate Variables override var popupHeight: CGFloat { height ?? 300.0 } @@ -22,4 +24,6 @@ class ExampleNavigationController: BottomPopupNavigationController { override var popupDismissDuration: Double { dismissDuration ?? 1.0 } override var popupShouldDismissInteractivelty: Bool { shouldDismissInteractivelty ?? true } override var popupDimmingViewAlpha: CGFloat { BottomPopupConstants.dimmingViewDefaultAlphaValue } + override var popupShouldBeganDismiss: Bool { shouldBeganDismiss ?? true } + override var popupShouldDismissOnTap: Bool { shouldDismissOnTap ?? true } } diff --git a/BottomPopup/ExamplePopupViewController.swift b/BottomPopup/ExamplePopupViewController.swift index 76c1b44..ef9753b 100644 --- a/BottomPopup/ExamplePopupViewController.swift +++ b/BottomPopup/ExamplePopupViewController.swift @@ -14,6 +14,8 @@ class ExamplePopupViewController: BottomPopupViewController { var presentDuration: Double? var dismissDuration: Double? var shouldDismissInteractivelty: Bool? + var shouldBeganDismiss: Bool? + var shouldDismissOnTap: Bool? @IBAction func dismissButtonTapped(_ sender: UIButton) { dismiss(animated: true, completion: nil) @@ -26,4 +28,6 @@ class ExamplePopupViewController: BottomPopupViewController { override var popupDismissDuration: Double { dismissDuration ?? 1.0 } override var popupShouldDismissInteractivelty: Bool { shouldDismissInteractivelty ?? true } override var popupDimmingViewAlpha: CGFloat { BottomPopupConstants.dimmingViewDefaultAlphaValue } + override var popupShouldBeganDismiss: Bool { shouldBeganDismiss ?? true } + override var popupShouldDismissOnTap: Bool { shouldDismissOnTap ?? true } } diff --git a/BottomPopup/ViewController.swift b/BottomPopup/ViewController.swift index 2cb353d..57e2e1e 100644 --- a/BottomPopup/ViewController.swift +++ b/BottomPopup/ViewController.swift @@ -18,6 +18,8 @@ class ViewController: UIViewController { @IBOutlet weak var topCornerRadiusLabel: UILabel! @IBOutlet weak var presentDurationLabel: UILabel! @IBOutlet weak var dismissDurationLabel: UILabel! + @IBOutlet weak var shouldBeganDismissSwitch: UISwitch! + @IBOutlet weak var dismissOnTapSwitch: UISwitch! var height: CGFloat = 300 { didSet { @@ -31,13 +33,13 @@ class ViewController: UIViewController { } } - var presentDuration: Double = 1.5 { + var presentDuration: Double = 0.5 { didSet { presentDurationLabel.text = String(format: "%.02f sec", presentDuration) } } - var dismissDuration: Double = 1.5 { + var dismissDuration: Double = 0.5 { didSet { dismissDurationLabel.text = String(format: "%.02f sec", dismissDuration) } @@ -83,6 +85,8 @@ class ViewController: UIViewController { popupViewController.presentDuration = presentDuration popupViewController.dismissDuration = dismissDuration popupViewController.shouldDismissInteractivelty = dismissInteractivelySwitch.isOn + popupViewController.shouldBeganDismiss = shouldBeganDismissSwitch.isOn + popupViewController.shouldDismissOnTap = dismissOnTapSwitch.isOn popupViewController.popupDelegate = self present(popupViewController, animated: true, completion: nil) } @@ -94,6 +98,8 @@ class ViewController: UIViewController { popupNavController.presentDuration = presentDuration popupNavController.dismissDuration = dismissDuration popupNavController.shouldDismissInteractivelty = dismissInteractivelySwitch.isOn + popupNavController.shouldBeganDismiss = shouldBeganDismissSwitch.isOn + popupNavController.shouldDismissOnTap = dismissOnTapSwitch.isOn present(popupNavController, animated: true, completion: nil) } }