Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 223ec2d2c0 | |||
| a0ca7e9e2a | |||
| f0a1914145 | |||
| 4355f5eb09 | |||
| 6b080f503d | |||
| c23ed83bf0 | |||
| 8b1c77d743 | |||
| 915ef85cff | |||
| dc1050be2a | |||
| 99ba8bf657 | |||
| 2b7e4198cf | |||
| 0969cceac8 | |||
| f349dea851 | |||
| b8e8f8d0ce | |||
| ee5f9ee9de | |||
| 8348cd6396 | |||
| 9f4c1be56d | |||
| de779aebef | |||
| 1785822242 | |||
| 1514ea5481 | |||
| ec81b9f5dd | |||
| 7381066b36 | |||
| bc998622eb | |||
| 97c8e8aa32 | |||
| 7be93d548e |
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
F437B75122D62D7700E6074C /* SPStorkControllerConfirmDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75022D62D7700E6074C /* SPStorkControllerConfirmDelegate.swift */; };
|
||||
F445CA8721AED92600184254 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F445CA8621AED92600184254 /* AppDelegate.swift */; };
|
||||
F445CA8921AED92600184254 /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = F445CA8821AED92600184254 /* Controller.swift */; };
|
||||
F445CA8E21AED92700184254 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F445CA8D21AED92700184254 /* Assets.xcassets */; };
|
||||
@@ -151,6 +152,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
F437B75022D62D7700E6074C /* SPStorkControllerConfirmDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPStorkControllerConfirmDelegate.swift; sourceTree = "<group>"; };
|
||||
F445CA8321AED92600184254 /* stork-controller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "stork-controller.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F445CA8621AED92600184254 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
F445CA8821AED92600184254 /* Controller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = "<group>"; };
|
||||
@@ -876,6 +878,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4E0E38F22CF6B940020D754 /* SPStorkControllerDelegate.swift */,
|
||||
F437B75022D62D7700E6074C /* SPStorkControllerConfirmDelegate.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
@@ -1086,6 +1089,7 @@
|
||||
F4DB84DB22609C05005082AA /* SPUserDefaultsExtenshion.swift in Sources */,
|
||||
F4DB849A22609C05005082AA /* SPFormLabelTableViewCell.swift in Sources */,
|
||||
F4DB84AD22609C05005082AA /* SPCircleCloseButton.swift in Sources */,
|
||||
F437B75122D62D7700E6074C /* SPStorkControllerConfirmDelegate.swift in Sources */,
|
||||
F4DB84AE22609C05005082AA /* SPAppStoreActionButton.swift in Sources */,
|
||||
F4E0E39C22CF6B940020D754 /* SPStorkControllerDelegate.swift in Sources */,
|
||||
F4DB84BB22609C05005082AA /* SPBlurView.swift in Sources */,
|
||||
|
||||
BIN
Binary file not shown.
@@ -28,6 +28,8 @@ class Controller: UIViewController {
|
||||
@objc func presentModalViewController() {
|
||||
let modal = ModalViewController()
|
||||
let transitionDelegate = SPStorkTransitioningDelegate()
|
||||
transitionDelegate.storkDelegate = self
|
||||
transitionDelegate.confirmDelegate = modal
|
||||
modal.transitioningDelegate = transitionDelegate
|
||||
modal.modalPresentationStyle = .custom
|
||||
self.present(modal, animated: true, completion: nil)
|
||||
@@ -36,8 +38,21 @@ class Controller: UIViewController {
|
||||
@objc func presentModalTableViewController() {
|
||||
let modal = ModalTableViewController()
|
||||
let transitionDelegate = SPStorkTransitioningDelegate()
|
||||
transitionDelegate.storkDelegate = self
|
||||
transitionDelegate.confirmDelegate = modal
|
||||
modal.transitioningDelegate = transitionDelegate
|
||||
modal.modalPresentationStyle = .custom
|
||||
self.present(modal, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension Controller: SPStorkControllerDelegate {
|
||||
|
||||
func didDismissStorkByTap() {
|
||||
print("SPStorkControllerDelegate - didDismissStorkByTap")
|
||||
}
|
||||
|
||||
func didDismissStorkBySwipe() {
|
||||
print("SPStorkControllerDelegate - didDismissStorkBySwipe")
|
||||
}
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// The MIT License (MIT)
|
||||
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc public protocol SPStorkControllerConfirmDelegate: class {
|
||||
|
||||
var needConfirm: Bool { get }
|
||||
|
||||
func confirm(_ completion: @escaping (_ isConfirmed: Bool)->())
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public enum SPStorkController {
|
||||
|
||||
static public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if let controller = self.controller(for: scrollView) {
|
||||
if let presentationController = controller.presentationController as? SPStorkPresentationController {
|
||||
if let presentationController = self.presentationController(for: controller) {
|
||||
let translation = -(scrollView.contentOffset.y + scrollView.contentInset.top)
|
||||
if translation >= 0 {
|
||||
if controller.isBeingPresented { return }
|
||||
@@ -35,7 +35,7 @@ public enum SPStorkController {
|
||||
presentationController.setIndicator(style: scrollView.isTracking ? .line : .arrow)
|
||||
if translation >= presentationController.translateForDismiss * 0.4 {
|
||||
if !scrollView.isTracking && !scrollView.isDragging {
|
||||
presentationController.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.dismissWithConfirmation(controller: controller, completion: {
|
||||
presentationController.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
return
|
||||
@@ -58,6 +58,14 @@ public enum SPStorkController {
|
||||
}
|
||||
}
|
||||
|
||||
static public func dismissWithConfirmation(controller: UIViewController, completion: (()->())?) {
|
||||
if let controller = self.presentationController(for: controller) {
|
||||
controller.dismissWithConfirmation(prepare: nil, completion: {
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static public var topScrollIndicatorInset: CGFloat {
|
||||
return 6
|
||||
}
|
||||
@@ -74,6 +82,19 @@ public enum SPStorkController {
|
||||
}
|
||||
}
|
||||
|
||||
static private func presentationController(for controller: UIViewController) -> SPStorkPresentationController? {
|
||||
guard controller.modalPresentationStyle == .custom else { return nil }
|
||||
|
||||
if let presentationController = controller.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
|
||||
if let presentationController = controller.parent?.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
static private func controller(for view: UIView) -> UIViewController? {
|
||||
var nextResponder = view.next
|
||||
while nextResponder != nil && !(nextResponder! is UIViewController) {
|
||||
|
||||
+91
-24
@@ -35,6 +35,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
var transitioningDelegate: SPStorkTransitioningDelegate?
|
||||
weak var storkDelegate: SPStorkControllerDelegate?
|
||||
weak var confirmDelegate: SPStorkControllerConfirmDelegate?
|
||||
|
||||
var pan: UIPanGestureRecognizer?
|
||||
var tap: UITapGestureRecognizer?
|
||||
@@ -50,6 +51,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
private var snapshotViewWidthConstraint: NSLayoutConstraint?
|
||||
private var snapshotViewAspectRatioConstraint: NSLayoutConstraint?
|
||||
|
||||
var workConfirmation: Bool = false
|
||||
private var workGester: Bool = false
|
||||
private var startDismissing: Bool = false
|
||||
private var afterReleaseDismissing: Bool = false
|
||||
@@ -68,7 +70,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
return factor
|
||||
}
|
||||
|
||||
private var feedbackGenerator: UIImpactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
private var feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
|
||||
override var presentedView: UIView? {
|
||||
let view = self.presentedViewController.view
|
||||
@@ -103,24 +105,42 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
guard let containerView = self.containerView, let presentedView = self.presentedView, let window = containerView.window else { return }
|
||||
|
||||
let closeTitle = NSLocalizedString("Close", comment: "Close")
|
||||
|
||||
if self.showIndicator {
|
||||
self.indicatorView.color = self.indicatorColor
|
||||
let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.dismissAction))
|
||||
let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.tapIndicator))
|
||||
tap.cancelsTouchesInView = false
|
||||
self.indicatorView.addGestureRecognizer(tap)
|
||||
self.indicatorView.accessibilityLabel = closeTitle
|
||||
presentedView.addSubview(self.indicatorView)
|
||||
self.indicatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.indicatorView.widthAnchor.constraint(equalToConstant: 36).isActive = true
|
||||
self.indicatorView.heightAnchor.constraint(equalToConstant: 13).isActive = true
|
||||
self.indicatorView.centerXAnchor.constraint(equalTo: presentedView.centerXAnchor).isActive = true
|
||||
self.indicatorView.topAnchor.constraint(equalTo: presentedView.topAnchor, constant: 12).isActive = true
|
||||
|
||||
if UIAccessibility.isVoiceOverRunning {
|
||||
let accessibleIndicatorOverlayButton = UIButton(type: .custom)
|
||||
accessibleIndicatorOverlayButton.addTarget(self, action: #selector(self.tapIndicator), for: .touchUpInside)
|
||||
accessibleIndicatorOverlayButton.accessibilityLabel = closeTitle
|
||||
presentedView.addSubview(accessibleIndicatorOverlayButton)
|
||||
accessibleIndicatorOverlayButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
accessibleIndicatorOverlayButton.leadingAnchor.constraint(equalTo: presentedView.leadingAnchor),
|
||||
accessibleIndicatorOverlayButton.trailingAnchor.constraint(equalTo: presentedView.trailingAnchor),
|
||||
accessibleIndicatorOverlayButton.topAnchor.constraint(equalTo: presentedView.topAnchor),
|
||||
accessibleIndicatorOverlayButton.bottomAnchor.constraint(equalTo: self.indicatorView.bottomAnchor),
|
||||
])
|
||||
}
|
||||
}
|
||||
self.updateLayoutIndicator()
|
||||
self.indicatorView.style = .arrow
|
||||
self.gradeView.alpha = 0
|
||||
|
||||
|
||||
self.closeButton.accessibilityLabel = closeTitle
|
||||
if self.showCloseButton {
|
||||
self.closeButton.addTarget(self, action: #selector(self.dismissAction), for: .touchUpInside)
|
||||
self.closeButton.addTarget(self, action: #selector(self.tapCloseButton), for: .touchUpInside)
|
||||
presentedView.addSubview(self.closeButton)
|
||||
}
|
||||
self.updateLayoutCloseButton()
|
||||
@@ -207,7 +227,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
self.updateSnapshotAspectRatio()
|
||||
|
||||
if self.tapAroundToDismissEnabled {
|
||||
self.tap = UITapGestureRecognizer.init(target: self, action: #selector(self.dismissAction))
|
||||
self.tap = UITapGestureRecognizer.init(target: self, action: #selector(self.tapArround))
|
||||
self.tap?.cancelsTouchesInView = false
|
||||
self.snapshotViewContainer.addGestureRecognizer(self.tap!)
|
||||
}
|
||||
@@ -221,21 +241,13 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
}
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
self.presentingViewController.view.endEditing(true)
|
||||
self.presentedViewController.view.endEditing(true)
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
override func dismissalTransitionWillBegin() {
|
||||
super.dismissalTransitionWillBegin()
|
||||
guard let containerView = containerView else { return }
|
||||
self.startDismissing = true
|
||||
|
||||
let initialFrame: CGRect = presentingViewController.isPresentedAsStork ? presentingViewController.view.frame : containerView.bounds
|
||||
|
||||
|
||||
let initialTransform = CGAffineTransform.identity
|
||||
.translatedBy(x: 0, y: -initialFrame.origin.y)
|
||||
.translatedBy(x: 0, y: self.topSpace)
|
||||
@@ -312,6 +324,56 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
extension SPStorkPresentationController {
|
||||
|
||||
@objc func tapIndicator() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
@objc func tapArround() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
@objc func tapCloseButton() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
public func dismissWithConfirmation(prepare: (()->())?, completion: (()->())?) {
|
||||
|
||||
let dismiss = {
|
||||
self.presentingViewController.view.endEditing(true)
|
||||
self.presentedViewController.view.endEditing(true)
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
|
||||
guard let confirmDelegate = self.confirmDelegate else {
|
||||
dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
if self.workConfirmation { return }
|
||||
|
||||
if confirmDelegate.needConfirm {
|
||||
prepare?()
|
||||
self.workConfirmation = true
|
||||
confirmDelegate.confirm({ (isConfirmed) in
|
||||
self.workConfirmation = false
|
||||
self.afterReleaseDismissing = false
|
||||
if isConfirmed {
|
||||
dismiss()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handlePan(gestureRecognizer: UIPanGestureRecognizer) {
|
||||
guard gestureRecognizer.isEqual(self.pan), self.swipeToDismissEnabled else { return }
|
||||
|
||||
@@ -334,11 +396,8 @@ extension SPStorkPresentationController {
|
||||
case .ended:
|
||||
self.workGester = false
|
||||
let translation = gestureRecognizer.translation(in: presentedView).y
|
||||
if translation >= self.translateForDismiss {
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
} else {
|
||||
|
||||
let toDefault = {
|
||||
self.indicatorView.style = .arrow
|
||||
UIView.animate(
|
||||
withDuration: 0.6,
|
||||
@@ -352,6 +411,14 @@ extension SPStorkPresentationController {
|
||||
self.gradeView.alpha = self.alpha
|
||||
})
|
||||
}
|
||||
|
||||
if translation >= self.translateForDismiss {
|
||||
self.dismissWithConfirmation(prepare: toDefault, completion: {
|
||||
self.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
} else {
|
||||
toDefault()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -401,7 +468,7 @@ extension SPStorkPresentationController {
|
||||
|
||||
let elasticThreshold: CGFloat = 120
|
||||
let translationFactor: CGFloat = 1 / 2
|
||||
|
||||
|
||||
if translation >= 0 {
|
||||
let translationForModal: CGFloat = {
|
||||
if translation >= elasticThreshold {
|
||||
@@ -427,8 +494,10 @@ extension SPStorkPresentationController {
|
||||
let afterRealseDismissing = (translation >= self.translateForDismiss)
|
||||
if afterRealseDismissing != self.afterReleaseDismissing {
|
||||
self.afterReleaseDismissing = afterRealseDismissing
|
||||
if self.hapticMoments.contains(.willDismissIfRelease) {
|
||||
self.feedbackGenerator.impactOccurred()
|
||||
if !self.workConfirmation {
|
||||
if self.hapticMoments.contains(.willDismissIfRelease) {
|
||||
self.feedbackGenerator.impactOccurred()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,8 +529,6 @@ extension SPStorkPresentationController {
|
||||
private func updateLayoutIndicator() {
|
||||
self.indicatorView.style = .line
|
||||
self.indicatorView.sizeToFit()
|
||||
//self.indicatorView.frame.origin.y = 12
|
||||
//self.indicatorView.center.x = presentedView.frame.width / 2
|
||||
}
|
||||
|
||||
private func updateLayoutCloseButton() {
|
||||
|
||||
+2
@@ -34,6 +34,7 @@ public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTrans
|
||||
public var cornerRadius: CGFloat = 10
|
||||
public var hapticMoments: [SPStorkHapticMoments] = [.willDismissIfRelease]
|
||||
public weak var storkDelegate: SPStorkControllerDelegate? = nil
|
||||
public weak var confirmDelegate: SPStorkControllerConfirmDelegate? = nil
|
||||
|
||||
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
|
||||
let controller = SPStorkPresentationController(presentedViewController: presented, presenting: presenting)
|
||||
@@ -49,6 +50,7 @@ public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTrans
|
||||
controller.hapticMoments = self.hapticMoments
|
||||
controller.transitioningDelegate = self
|
||||
controller.storkDelegate = self.storkDelegate
|
||||
controller.confirmDelegate = self.confirmDelegate
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
|
||||
var isDarkMode: Bool {
|
||||
if #available(iOS 12.0, *) {
|
||||
if self.traitCollection.userInterfaceStyle == .dark {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
var viewController: UIViewController? {
|
||||
|
||||
+2
-1
@@ -63,7 +63,7 @@ struct SPLocalNotification {
|
||||
|
||||
if let category = self.category {
|
||||
if #available(iOS 12.0, *) {
|
||||
let notificationCategory = UNNotificationCategory(identifier: category.identifier, actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: nil, categorySummaryFormat: category.summary, options: [])
|
||||
let notificationCategory = UNNotificationCategory(identifier: category.identifier, actions: category.actions, intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: nil, categorySummaryFormat: category.summary, options: [])
|
||||
UNUserNotificationCenter.current().setNotificationCategories([notificationCategory])
|
||||
content.categoryIdentifier = notificationCategory.identifier
|
||||
}
|
||||
@@ -81,6 +81,7 @@ struct SPLocalNotificationCategory {
|
||||
|
||||
var identifier: String
|
||||
var summary: String
|
||||
var actions: [UNNotificationAction] = []
|
||||
|
||||
static var countSymbol: String {
|
||||
return "%u"
|
||||
|
||||
@@ -24,8 +24,9 @@ import UIKit
|
||||
class SPFooterActionsView: SPView {
|
||||
|
||||
var sectionLabels = SPSectionLabelsView()
|
||||
private var buttons: [SPFooterActionButton] = []
|
||||
private var separators: [SPSeparatorView] = []
|
||||
|
||||
var buttons: [SPFooterActionButton] = []
|
||||
var separators: [SPSeparatorView] = []
|
||||
|
||||
override func commonInit() {
|
||||
super.commonInit()
|
||||
|
||||
@@ -49,7 +49,7 @@ class ModalTableViewController: UIViewController {
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
self.dismiss()
|
||||
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,3 +79,20 @@ extension ModalTableViewController: UITableViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
extension ModalTableViewController: SPStorkControllerConfirmDelegate {
|
||||
|
||||
var needConfirm: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func confirm(_ completion: @escaping (Bool) -> ()) {
|
||||
let alertController = UIAlertController(title: "Need dismiss?", message: "It test confirm option for SPStorkController", preferredStyle: .actionSheet)
|
||||
alertController.addDestructiveAction(title: "Confirm", complection: {
|
||||
completion(true)
|
||||
})
|
||||
alertController.addCancelAction(title: "Cancel") {
|
||||
completion(false)
|
||||
}
|
||||
self.present(alertController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class ModalViewController: UIViewController {
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
self.dismiss()
|
||||
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@@ -32,3 +32,20 @@ class ModalViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
extension ModalViewController: SPStorkControllerConfirmDelegate {
|
||||
|
||||
var needConfirm: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func confirm(_ completion: @escaping (Bool) -> ()) {
|
||||
let alertController = UIAlertController(title: "Need dismiss?", message: "It test confirm option for SPStorkController", preferredStyle: .actionSheet)
|
||||
alertController.addDestructiveAction(title: "Confirm", complection: {
|
||||
completion(true)
|
||||
})
|
||||
alertController.addCancelAction(title: "Cancel") {
|
||||
completion(false)
|
||||
}
|
||||
self.present(alertController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,29 +9,32 @@ You can download example [Debts - Spending tracker](https://itunes.apple.com/app
|
||||
|
||||
[](https://xcode-shop.com)
|
||||
|
||||
If you like the project, do not forget to `put star ★` or follow me in twitter:
|
||||
If you like the project, do not forget to `put star ★` and follow me on GitHub:
|
||||
|
||||
[](https://twitter.com/varabeis)
|
||||
|
||||
See project's backers in [Sponsors](https://github.com/ivanvorobei/SPStorkController#sponsors) section.
|
||||
[](https://github.com/ivanvorobei)
|
||||
|
||||
## Navigate
|
||||
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [CocoaPods](#cocoapods)
|
||||
- [Carthage](#carthage)
|
||||
- [Swift Package Manager](#swift-package-manager)
|
||||
- [Manually](#manually)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Usage](#usage)
|
||||
- [Light StatusBar](#light-statusbar)
|
||||
- [Custom Height](#custom-height)
|
||||
- [Close Button](#close-button)
|
||||
- [Indicator](#indicator)
|
||||
- [Arrow Indicator](#arrow-indicator)
|
||||
- [Dismissing](#dismissing)
|
||||
- [Corner Radius](#corner-radius)
|
||||
- [Haptic](#haptic)
|
||||
- [Snapshots](#snapshots)
|
||||
- [Add Navigation Bar](#add-navigation-bar)
|
||||
- [Navigation Bar](#navigation-bar)
|
||||
- [Working with UIScrollView](#working-with-uiscrollview)
|
||||
- [UITableView & UICollectionView](#working-with-uitableview--uicollectionview)
|
||||
- [Confirm before dismiss](#confirm-before-dismiss)
|
||||
- [Delegate](#delegate)
|
||||
- [Storyboard](#storyboard)
|
||||
- [Sheets in iOS 13](#sheets-in-ios-13)
|
||||
@@ -149,7 +152,7 @@ Property `showCloseButton` added circle button with dismiss action. Default is `
|
||||
transitionDelegate.showCloseButton = false
|
||||
```
|
||||
|
||||
### Indicator
|
||||
### Arrow Indicator
|
||||
|
||||
On the top of controller you can add arrow indicator with animatable states. It simple configure.
|
||||
Property `showIndicator` shows or hides top arrow indicator. Default is `true`:
|
||||
@@ -217,7 +220,13 @@ SPStorkController.updatePresentingController(modal: controller)
|
||||
|
||||
and pass the controller, which is modal and uses `SPStorkTransitioningDelegate`.
|
||||
|
||||
### Add Navigation Bar
|
||||
If the parent controller scrollings and you try to show `SPStorkController`, you will see how it froze, and in a second its final position is updated. I recommend before present `SPStorkController` stop scrolling force:
|
||||
|
||||
```swift
|
||||
scrollView.setContentOffset(self.contentOffset, animated: false)
|
||||
```
|
||||
|
||||
### Navigation Bar
|
||||
|
||||
You may want to add a navigation bar to your modal controller. Since it became impossible to change or customize the native controller in swift 4 (I couldn’t even find a way to change the height of the bar), I had to recreate navigation bar from the ground up. Visually it looks real, but it doesn’t execute the necessary functions:
|
||||
|
||||
@@ -276,6 +285,29 @@ tableView.scrollIndicatorInsets.top = self.navBar.height
|
||||
|
||||
Please, also use `SPStorkController.scrollViewDidScroll` function in scroll delegate for more interactiveness with your collection or table view.
|
||||
|
||||
### Confirm before dismiss
|
||||
|
||||
For confirm closing by swipe, tap around, close button and indicator use `SPStorkControllerConfirmDelegate`. Implenet protocol:
|
||||
|
||||
```swift
|
||||
@objc public protocol SPStorkControllerConfirmDelegate: class {
|
||||
|
||||
var needConfirm: Bool { get }
|
||||
|
||||
func confirm(_ completion: @escaping (_ isConfirmed: Bool)->())
|
||||
}
|
||||
```
|
||||
|
||||
and set `confirmDelegate` property to object, which protocol impleneted. Function `confirm` call if `needConfirm` return true. Pass `isConfirmed` with result. Best options use `UIAlertController` with `.actionSheet` style for confirmation.
|
||||
|
||||
If you use custom buttons, in the target use this code:
|
||||
|
||||
```swift
|
||||
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
|
||||
```
|
||||
|
||||
It call `confirm` func and check result of confirmation. See example project for more details.
|
||||
|
||||
### Delegate
|
||||
|
||||
You can check events by implement `SPStorkControllerDelegate` and set delegate for `transitionDelegate`:
|
||||
@@ -327,14 +359,6 @@ controller.modalPresentationStyle = .custom
|
||||
|
||||
It’s needed for correct presentation and dismissal of all modal controllers.
|
||||
|
||||
### Stop scroll
|
||||
|
||||
`SPStorkController` use snapshots. If the parent controller scrollings and you try to show `SPStorkController`, you will see how it froze, and in a second its final position is updated. I recommend to stop scrolling force:
|
||||
|
||||
```swift
|
||||
scrollView.setContentOffset(self.contentOffset, animated: false)
|
||||
```
|
||||
|
||||
## Sheets in iOS 13
|
||||
|
||||
Apple present in `WWDC 2019` new modal presentation style - `Sheets`. It ready use Support interactive dismiss and work with navigations bars. Available since iOS 13. I will add more information when I study this in more detail. You can see presentation [here](https://developer.apple.com/videos/play/wwdc2019/224/).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "SPStorkController"
|
||||
s.version = "1.6.7"
|
||||
s.version = "1.7.7"
|
||||
s.summary = "Very similar to the controllers displayed in Apple Music, Podcasts and Mail Apple's applications."
|
||||
s.homepage = "https://github.com/IvanVorobei/SPStorkController"
|
||||
s.source = { :git => "https://github.com/IvanVorobei/SPStorkController.git", :tag => s.version }
|
||||
|
||||
@@ -7,39 +7,41 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
F437B76722D62FF000E6074C /* SPStorkHaptic.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75422D62FF000E6074C /* SPStorkHaptic.swift */; };
|
||||
F437B76822D62FF000E6074C /* SPStorkSeque.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75522D62FF000E6074C /* SPStorkSeque.swift */; };
|
||||
F437B76922D62FF000E6074C /* SPStorkCodeDraw.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75722D62FF000E6074C /* SPStorkCodeDraw.swift */; };
|
||||
F437B76A22D62FF000E6074C /* SPStorkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75822D62FF000E6074C /* SPStorkController.swift */; };
|
||||
F437B76B22D62FF000E6074C /* SPStorkTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75A22D62FF000E6074C /* SPStorkTransitioningDelegate.swift */; };
|
||||
F437B76C22D62FF000E6074C /* SPStorkPresentingAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75B22D62FF000E6074C /* SPStorkPresentingAnimationController.swift */; };
|
||||
F437B76D22D62FF000E6074C /* SPStorkPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75C22D62FF000E6074C /* SPStorkPresentationController.swift */; };
|
||||
F437B76E22D62FF000E6074C /* SPStorkDismissingAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75D22D62FF000E6074C /* SPStorkDismissingAnimationController.swift */; };
|
||||
F437B76F22D62FF000E6074C /* SPStorkViewControllerExtenshion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B75F22D62FF000E6074C /* SPStorkViewControllerExtenshion.swift */; };
|
||||
F437B77022D62FF000E6074C /* SPStorkCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B76122D62FF000E6074C /* SPStorkCloseButton.swift */; };
|
||||
F437B77122D62FF000E6074C /* SPStorkIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B76222D62FF000E6074C /* SPStorkIndicatorView.swift */; };
|
||||
F437B77222D62FF000E6074C /* SPStorkCloseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B76322D62FF000E6074C /* SPStorkCloseView.swift */; };
|
||||
F437B77322D62FF000E6074C /* SPStorkControllerConfirmDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B76522D62FF000E6074C /* SPStorkControllerConfirmDelegate.swift */; };
|
||||
F437B77422D62FF000E6074C /* SPStorkControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F437B76622D62FF000E6074C /* SPStorkControllerDelegate.swift */; };
|
||||
F4DB85222260A4FD005082AA /* SPStorkController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4DB85202260A4FD005082AA /* SPStorkController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F4EF61BC22B58B8600E76099 /* SPStorkHaptic.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61AA22B58B8500E76099 /* SPStorkHaptic.swift */; };
|
||||
F4EF61BD22B58B8600E76099 /* SPStorkSeque.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61AB22B58B8500E76099 /* SPStorkSeque.swift */; };
|
||||
F4EF61BE22B58B8600E76099 /* SPStorkCodeDraw.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61AD22B58B8500E76099 /* SPStorkCodeDraw.swift */; };
|
||||
F4EF61BF22B58B8600E76099 /* SPStorkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61AE22B58B8500E76099 /* SPStorkController.swift */; };
|
||||
F4EF61C022B58B8600E76099 /* SPStorkTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B022B58B8500E76099 /* SPStorkTransitioningDelegate.swift */; };
|
||||
F4EF61C122B58B8600E76099 /* SPStorkPresentingAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B122B58B8500E76099 /* SPStorkPresentingAnimationController.swift */; };
|
||||
F4EF61C222B58B8600E76099 /* SPStorkPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B222B58B8500E76099 /* SPStorkPresentationController.swift */; };
|
||||
F4EF61C322B58B8600E76099 /* SPStorkDismissingAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B322B58B8500E76099 /* SPStorkDismissingAnimationController.swift */; };
|
||||
F4EF61C422B58B8600E76099 /* SPStorkViewControllerExtenshion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B522B58B8500E76099 /* SPStorkViewControllerExtenshion.swift */; };
|
||||
F4EF61C522B58B8600E76099 /* SPStorkCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B722B58B8500E76099 /* SPStorkCloseButton.swift */; };
|
||||
F4EF61C622B58B8600E76099 /* SPStorkIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B822B58B8500E76099 /* SPStorkIndicatorView.swift */; };
|
||||
F4EF61C722B58B8600E76099 /* SPStorkCloseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61B922B58B8500E76099 /* SPStorkCloseView.swift */; };
|
||||
F4EF61C822B58B8600E76099 /* SPStorkControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EF61BB22B58B8500E76099 /* SPStorkControllerDelegate.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
F437B75422D62FF000E6074C /* SPStorkHaptic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkHaptic.swift; sourceTree = "<group>"; };
|
||||
F437B75522D62FF000E6074C /* SPStorkSeque.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkSeque.swift; sourceTree = "<group>"; };
|
||||
F437B75722D62FF000E6074C /* SPStorkCodeDraw.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCodeDraw.swift; sourceTree = "<group>"; };
|
||||
F437B75822D62FF000E6074C /* SPStorkController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkController.swift; sourceTree = "<group>"; };
|
||||
F437B75A22D62FF000E6074C /* SPStorkTransitioningDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkTransitioningDelegate.swift; sourceTree = "<group>"; };
|
||||
F437B75B22D62FF000E6074C /* SPStorkPresentingAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkPresentingAnimationController.swift; sourceTree = "<group>"; };
|
||||
F437B75C22D62FF000E6074C /* SPStorkPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkPresentationController.swift; sourceTree = "<group>"; };
|
||||
F437B75D22D62FF000E6074C /* SPStorkDismissingAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkDismissingAnimationController.swift; sourceTree = "<group>"; };
|
||||
F437B75F22D62FF000E6074C /* SPStorkViewControllerExtenshion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkViewControllerExtenshion.swift; sourceTree = "<group>"; };
|
||||
F437B76122D62FF000E6074C /* SPStorkCloseButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCloseButton.swift; sourceTree = "<group>"; };
|
||||
F437B76222D62FF000E6074C /* SPStorkIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkIndicatorView.swift; sourceTree = "<group>"; };
|
||||
F437B76322D62FF000E6074C /* SPStorkCloseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCloseView.swift; sourceTree = "<group>"; };
|
||||
F437B76522D62FF000E6074C /* SPStorkControllerConfirmDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkControllerConfirmDelegate.swift; sourceTree = "<group>"; };
|
||||
F437B76622D62FF000E6074C /* SPStorkControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkControllerDelegate.swift; sourceTree = "<group>"; };
|
||||
F4DB851D2260A4FD005082AA /* SPStorkController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SPStorkController.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F4DB85202260A4FD005082AA /* SPStorkController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SPStorkController.h; sourceTree = "<group>"; };
|
||||
F4DB85212260A4FD005082AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
F4EF61AA22B58B8500E76099 /* SPStorkHaptic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkHaptic.swift; sourceTree = "<group>"; };
|
||||
F4EF61AB22B58B8500E76099 /* SPStorkSeque.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkSeque.swift; sourceTree = "<group>"; };
|
||||
F4EF61AD22B58B8500E76099 /* SPStorkCodeDraw.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCodeDraw.swift; sourceTree = "<group>"; };
|
||||
F4EF61AE22B58B8500E76099 /* SPStorkController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkController.swift; sourceTree = "<group>"; };
|
||||
F4EF61B022B58B8500E76099 /* SPStorkTransitioningDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkTransitioningDelegate.swift; sourceTree = "<group>"; };
|
||||
F4EF61B122B58B8500E76099 /* SPStorkPresentingAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkPresentingAnimationController.swift; sourceTree = "<group>"; };
|
||||
F4EF61B222B58B8500E76099 /* SPStorkPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkPresentationController.swift; sourceTree = "<group>"; };
|
||||
F4EF61B322B58B8500E76099 /* SPStorkDismissingAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkDismissingAnimationController.swift; sourceTree = "<group>"; };
|
||||
F4EF61B522B58B8500E76099 /* SPStorkViewControllerExtenshion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkViewControllerExtenshion.swift; sourceTree = "<group>"; };
|
||||
F4EF61B722B58B8500E76099 /* SPStorkCloseButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCloseButton.swift; sourceTree = "<group>"; };
|
||||
F4EF61B822B58B8500E76099 /* SPStorkIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkIndicatorView.swift; sourceTree = "<group>"; };
|
||||
F4EF61B922B58B8500E76099 /* SPStorkCloseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkCloseView.swift; sourceTree = "<group>"; };
|
||||
F4EF61BB22B58B8500E76099 /* SPStorkControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SPStorkControllerDelegate.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -53,6 +55,75 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
F437B75222D62FF000E6074C /* SPStorkController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B75322D62FF000E6074C /* Models */,
|
||||
F437B75522D62FF000E6074C /* SPStorkSeque.swift */,
|
||||
F437B75622D62FF000E6074C /* CodeDraw */,
|
||||
F437B75822D62FF000E6074C /* SPStorkController.swift */,
|
||||
F437B75922D62FF000E6074C /* TransitioningDelegate */,
|
||||
F437B75E22D62FF000E6074C /* Extenshion */,
|
||||
F437B76022D62FF000E6074C /* Views */,
|
||||
F437B76422D62FF000E6074C /* Protocols */,
|
||||
);
|
||||
path = SPStorkController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B75322D62FF000E6074C /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B75422D62FF000E6074C /* SPStorkHaptic.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B75622D62FF000E6074C /* CodeDraw */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B75722D62FF000E6074C /* SPStorkCodeDraw.swift */,
|
||||
);
|
||||
path = CodeDraw;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B75922D62FF000E6074C /* TransitioningDelegate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B75A22D62FF000E6074C /* SPStorkTransitioningDelegate.swift */,
|
||||
F437B75B22D62FF000E6074C /* SPStorkPresentingAnimationController.swift */,
|
||||
F437B75C22D62FF000E6074C /* SPStorkPresentationController.swift */,
|
||||
F437B75D22D62FF000E6074C /* SPStorkDismissingAnimationController.swift */,
|
||||
);
|
||||
path = TransitioningDelegate;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B75E22D62FF000E6074C /* Extenshion */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B75F22D62FF000E6074C /* SPStorkViewControllerExtenshion.swift */,
|
||||
);
|
||||
path = Extenshion;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B76022D62FF000E6074C /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B76122D62FF000E6074C /* SPStorkCloseButton.swift */,
|
||||
F437B76222D62FF000E6074C /* SPStorkIndicatorView.swift */,
|
||||
F437B76322D62FF000E6074C /* SPStorkCloseView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F437B76422D62FF000E6074C /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F437B76522D62FF000E6074C /* SPStorkControllerConfirmDelegate.swift */,
|
||||
F437B76622D62FF000E6074C /* SPStorkControllerDelegate.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4437E4F22B50918006E6498 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -81,80 +152,12 @@
|
||||
F4DB851F2260A4FD005082AA /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61A822B58B8500E76099 /* SPStorkController */,
|
||||
F437B75222D62FF000E6074C /* SPStorkController */,
|
||||
F4437E4F22B50918006E6498 /* Supporting Files */,
|
||||
);
|
||||
path = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61A822B58B8500E76099 /* SPStorkController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61A922B58B8500E76099 /* Models */,
|
||||
F4EF61AB22B58B8500E76099 /* SPStorkSeque.swift */,
|
||||
F4EF61AC22B58B8500E76099 /* CodeDraw */,
|
||||
F4EF61AE22B58B8500E76099 /* SPStorkController.swift */,
|
||||
F4EF61AF22B58B8500E76099 /* TransitioningDelegate */,
|
||||
F4EF61B422B58B8500E76099 /* Extenshion */,
|
||||
F4EF61B622B58B8500E76099 /* Views */,
|
||||
F4EF61BA22B58B8500E76099 /* Protocols */,
|
||||
);
|
||||
path = SPStorkController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61A922B58B8500E76099 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61AA22B58B8500E76099 /* SPStorkHaptic.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61AC22B58B8500E76099 /* CodeDraw */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61AD22B58B8500E76099 /* SPStorkCodeDraw.swift */,
|
||||
);
|
||||
path = CodeDraw;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61AF22B58B8500E76099 /* TransitioningDelegate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61B022B58B8500E76099 /* SPStorkTransitioningDelegate.swift */,
|
||||
F4EF61B122B58B8500E76099 /* SPStorkPresentingAnimationController.swift */,
|
||||
F4EF61B222B58B8500E76099 /* SPStorkPresentationController.swift */,
|
||||
F4EF61B322B58B8500E76099 /* SPStorkDismissingAnimationController.swift */,
|
||||
);
|
||||
path = TransitioningDelegate;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61B422B58B8500E76099 /* Extenshion */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61B522B58B8500E76099 /* SPStorkViewControllerExtenshion.swift */,
|
||||
);
|
||||
path = Extenshion;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61B622B58B8500E76099 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61B722B58B8500E76099 /* SPStorkCloseButton.swift */,
|
||||
F4EF61B822B58B8500E76099 /* SPStorkIndicatorView.swift */,
|
||||
F4EF61B922B58B8500E76099 /* SPStorkCloseView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F4EF61BA22B58B8500E76099 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F4EF61BB22B58B8500E76099 /* SPStorkControllerDelegate.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -233,19 +236,20 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F4EF61BF22B58B8600E76099 /* SPStorkController.swift in Sources */,
|
||||
F4EF61C322B58B8600E76099 /* SPStorkDismissingAnimationController.swift in Sources */,
|
||||
F4EF61C222B58B8600E76099 /* SPStorkPresentationController.swift in Sources */,
|
||||
F4EF61C422B58B8600E76099 /* SPStorkViewControllerExtenshion.swift in Sources */,
|
||||
F4EF61BD22B58B8600E76099 /* SPStorkSeque.swift in Sources */,
|
||||
F4EF61C522B58B8600E76099 /* SPStorkCloseButton.swift in Sources */,
|
||||
F4EF61C822B58B8600E76099 /* SPStorkControllerDelegate.swift in Sources */,
|
||||
F4EF61C122B58B8600E76099 /* SPStorkPresentingAnimationController.swift in Sources */,
|
||||
F4EF61C622B58B8600E76099 /* SPStorkIndicatorView.swift in Sources */,
|
||||
F4EF61C722B58B8600E76099 /* SPStorkCloseView.swift in Sources */,
|
||||
F4EF61BE22B58B8600E76099 /* SPStorkCodeDraw.swift in Sources */,
|
||||
F4EF61BC22B58B8600E76099 /* SPStorkHaptic.swift in Sources */,
|
||||
F4EF61C022B58B8600E76099 /* SPStorkTransitioningDelegate.swift in Sources */,
|
||||
F437B76A22D62FF000E6074C /* SPStorkController.swift in Sources */,
|
||||
F437B76E22D62FF000E6074C /* SPStorkDismissingAnimationController.swift in Sources */,
|
||||
F437B76D22D62FF000E6074C /* SPStorkPresentationController.swift in Sources */,
|
||||
F437B76F22D62FF000E6074C /* SPStorkViewControllerExtenshion.swift in Sources */,
|
||||
F437B76822D62FF000E6074C /* SPStorkSeque.swift in Sources */,
|
||||
F437B77422D62FF000E6074C /* SPStorkControllerDelegate.swift in Sources */,
|
||||
F437B77322D62FF000E6074C /* SPStorkControllerConfirmDelegate.swift in Sources */,
|
||||
F437B77022D62FF000E6074C /* SPStorkCloseButton.swift in Sources */,
|
||||
F437B76C22D62FF000E6074C /* SPStorkPresentingAnimationController.swift in Sources */,
|
||||
F437B77122D62FF000E6074C /* SPStorkIndicatorView.swift in Sources */,
|
||||
F437B77222D62FF000E6074C /* SPStorkCloseView.swift in Sources */,
|
||||
F437B76922D62FF000E6074C /* SPStorkCodeDraw.swift in Sources */,
|
||||
F437B76722D62FF000E6074C /* SPStorkHaptic.swift in Sources */,
|
||||
F437B76B22D62FF000E6074C /* SPStorkTransitioningDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// The MIT License (MIT)
|
||||
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc public protocol SPStorkControllerConfirmDelegate: class {
|
||||
|
||||
var needConfirm: Bool { get }
|
||||
|
||||
func confirm(_ completion: @escaping (_ isConfirmed: Bool)->())
|
||||
}
|
||||
@@ -22,17 +22,20 @@
|
||||
import UIKit
|
||||
|
||||
public enum SPStorkController {
|
||||
|
||||
static public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if let controller = self.controller(for: scrollView) {
|
||||
if let presentationController = self.presentationController(for: controller) {
|
||||
let translation = -(scrollView.contentOffset.y + scrollView.contentInset.top)
|
||||
if translation >= 0 {
|
||||
if controller.isBeingPresented { return }
|
||||
scrollView.transform = CGAffineTransform(translationX: 0, y: -translation)
|
||||
scrollView.subviews.forEach {
|
||||
$0.transform = CGAffineTransform(translationX: 0, y: -translation)
|
||||
}
|
||||
presentationController.setIndicator(style: scrollView.isTracking ? .line : .arrow)
|
||||
if translation >= presentationController.translateForDismiss * 0.4 {
|
||||
if !scrollView.isTracking && !scrollView.isDragging {
|
||||
presentationController.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.dismissWithConfirmation(controller: controller, completion: {
|
||||
presentationController.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
return
|
||||
@@ -55,6 +58,14 @@ public enum SPStorkController {
|
||||
}
|
||||
}
|
||||
|
||||
static public func dismissWithConfirmation(controller: UIViewController, completion: (()->())?) {
|
||||
if let controller = self.presentationController(for: controller) {
|
||||
controller.dismissWithConfirmation(prepare: nil, completion: {
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static public var topScrollIndicatorInset: CGFloat {
|
||||
return 6
|
||||
}
|
||||
@@ -72,6 +83,8 @@ public enum SPStorkController {
|
||||
}
|
||||
|
||||
static private func presentationController(for controller: UIViewController) -> SPStorkPresentationController? {
|
||||
guard controller.modalPresentationStyle == .custom else { return nil }
|
||||
|
||||
if let presentationController = controller.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
@@ -79,7 +92,6 @@ public enum SPStorkController {
|
||||
if let presentationController = controller.parent?.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+91
-24
@@ -35,6 +35,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
var transitioningDelegate: SPStorkTransitioningDelegate?
|
||||
weak var storkDelegate: SPStorkControllerDelegate?
|
||||
weak var confirmDelegate: SPStorkControllerConfirmDelegate?
|
||||
|
||||
var pan: UIPanGestureRecognizer?
|
||||
var tap: UITapGestureRecognizer?
|
||||
@@ -50,6 +51,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
private var snapshotViewWidthConstraint: NSLayoutConstraint?
|
||||
private var snapshotViewAspectRatioConstraint: NSLayoutConstraint?
|
||||
|
||||
var workConfirmation: Bool = false
|
||||
private var workGester: Bool = false
|
||||
private var startDismissing: Bool = false
|
||||
private var afterReleaseDismissing: Bool = false
|
||||
@@ -68,7 +70,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
return factor
|
||||
}
|
||||
|
||||
private var feedbackGenerator: UIImpactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
private var feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
|
||||
override var presentedView: UIView? {
|
||||
let view = self.presentedViewController.view
|
||||
@@ -103,24 +105,42 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
guard let containerView = self.containerView, let presentedView = self.presentedView, let window = containerView.window else { return }
|
||||
|
||||
let closeTitle = NSLocalizedString("Close", comment: "Close")
|
||||
|
||||
if self.showIndicator {
|
||||
self.indicatorView.color = self.indicatorColor
|
||||
let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.dismissAction))
|
||||
let tap = UITapGestureRecognizer.init(target: self, action: #selector(self.tapIndicator))
|
||||
tap.cancelsTouchesInView = false
|
||||
self.indicatorView.addGestureRecognizer(tap)
|
||||
self.indicatorView.accessibilityLabel = closeTitle
|
||||
presentedView.addSubview(self.indicatorView)
|
||||
self.indicatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.indicatorView.widthAnchor.constraint(equalToConstant: 36).isActive = true
|
||||
self.indicatorView.heightAnchor.constraint(equalToConstant: 13).isActive = true
|
||||
self.indicatorView.centerXAnchor.constraint(equalTo: presentedView.centerXAnchor).isActive = true
|
||||
self.indicatorView.topAnchor.constraint(equalTo: presentedView.topAnchor, constant: 12).isActive = true
|
||||
|
||||
if UIAccessibility.isVoiceOverRunning {
|
||||
let accessibleIndicatorOverlayButton = UIButton(type: .custom)
|
||||
accessibleIndicatorOverlayButton.addTarget(self, action: #selector(self.tapIndicator), for: .touchUpInside)
|
||||
accessibleIndicatorOverlayButton.accessibilityLabel = closeTitle
|
||||
presentedView.addSubview(accessibleIndicatorOverlayButton)
|
||||
accessibleIndicatorOverlayButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
accessibleIndicatorOverlayButton.leadingAnchor.constraint(equalTo: presentedView.leadingAnchor),
|
||||
accessibleIndicatorOverlayButton.trailingAnchor.constraint(equalTo: presentedView.trailingAnchor),
|
||||
accessibleIndicatorOverlayButton.topAnchor.constraint(equalTo: presentedView.topAnchor),
|
||||
accessibleIndicatorOverlayButton.bottomAnchor.constraint(equalTo: self.indicatorView.bottomAnchor),
|
||||
])
|
||||
}
|
||||
}
|
||||
self.updateLayoutIndicator()
|
||||
self.indicatorView.style = .arrow
|
||||
self.gradeView.alpha = 0
|
||||
|
||||
|
||||
self.closeButton.accessibilityLabel = closeTitle
|
||||
if self.showCloseButton {
|
||||
self.closeButton.addTarget(self, action: #selector(self.dismissAction), for: .touchUpInside)
|
||||
self.closeButton.addTarget(self, action: #selector(self.tapCloseButton), for: .touchUpInside)
|
||||
presentedView.addSubview(self.closeButton)
|
||||
}
|
||||
self.updateLayoutCloseButton()
|
||||
@@ -207,7 +227,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
self.updateSnapshotAspectRatio()
|
||||
|
||||
if self.tapAroundToDismissEnabled {
|
||||
self.tap = UITapGestureRecognizer.init(target: self, action: #selector(self.dismissAction))
|
||||
self.tap = UITapGestureRecognizer.init(target: self, action: #selector(self.tapArround))
|
||||
self.tap?.cancelsTouchesInView = false
|
||||
self.snapshotViewContainer.addGestureRecognizer(self.tap!)
|
||||
}
|
||||
@@ -221,21 +241,13 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
}
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
self.presentingViewController.view.endEditing(true)
|
||||
self.presentedViewController.view.endEditing(true)
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
override func dismissalTransitionWillBegin() {
|
||||
super.dismissalTransitionWillBegin()
|
||||
guard let containerView = containerView else { return }
|
||||
self.startDismissing = true
|
||||
|
||||
let initialFrame: CGRect = presentingViewController.isPresentedAsStork ? presentingViewController.view.frame : containerView.bounds
|
||||
|
||||
|
||||
let initialTransform = CGAffineTransform.identity
|
||||
.translatedBy(x: 0, y: -initialFrame.origin.y)
|
||||
.translatedBy(x: 0, y: self.topSpace)
|
||||
@@ -312,6 +324,56 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
|
||||
|
||||
extension SPStorkPresentationController {
|
||||
|
||||
@objc func tapIndicator() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
@objc func tapArround() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
@objc func tapCloseButton() {
|
||||
self.dismissWithConfirmation(prepare: nil, completion: {
|
||||
self.storkDelegate?.didDismissStorkByTap?()
|
||||
})
|
||||
}
|
||||
|
||||
public func dismissWithConfirmation(prepare: (()->())?, completion: (()->())?) {
|
||||
|
||||
let dismiss = {
|
||||
self.presentingViewController.view.endEditing(true)
|
||||
self.presentedViewController.view.endEditing(true)
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
|
||||
guard let confirmDelegate = self.confirmDelegate else {
|
||||
dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
if self.workConfirmation { return }
|
||||
|
||||
if confirmDelegate.needConfirm {
|
||||
prepare?()
|
||||
self.workConfirmation = true
|
||||
confirmDelegate.confirm({ (isConfirmed) in
|
||||
self.workConfirmation = false
|
||||
self.afterReleaseDismissing = false
|
||||
if isConfirmed {
|
||||
dismiss()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func handlePan(gestureRecognizer: UIPanGestureRecognizer) {
|
||||
guard gestureRecognizer.isEqual(self.pan), self.swipeToDismissEnabled else { return }
|
||||
|
||||
@@ -334,11 +396,8 @@ extension SPStorkPresentationController {
|
||||
case .ended:
|
||||
self.workGester = false
|
||||
let translation = gestureRecognizer.translation(in: presentedView).y
|
||||
if translation >= self.translateForDismiss {
|
||||
self.presentedViewController.dismiss(animated: true, completion: {
|
||||
self.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
} else {
|
||||
|
||||
let toDefault = {
|
||||
self.indicatorView.style = .arrow
|
||||
UIView.animate(
|
||||
withDuration: 0.6,
|
||||
@@ -352,6 +411,14 @@ extension SPStorkPresentationController {
|
||||
self.gradeView.alpha = self.alpha
|
||||
})
|
||||
}
|
||||
|
||||
if translation >= self.translateForDismiss {
|
||||
self.dismissWithConfirmation(prepare: toDefault, completion: {
|
||||
self.storkDelegate?.didDismissStorkBySwipe?()
|
||||
})
|
||||
} else {
|
||||
toDefault()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -401,7 +468,7 @@ extension SPStorkPresentationController {
|
||||
|
||||
let elasticThreshold: CGFloat = 120
|
||||
let translationFactor: CGFloat = 1 / 2
|
||||
|
||||
|
||||
if translation >= 0 {
|
||||
let translationForModal: CGFloat = {
|
||||
if translation >= elasticThreshold {
|
||||
@@ -427,8 +494,10 @@ extension SPStorkPresentationController {
|
||||
let afterRealseDismissing = (translation >= self.translateForDismiss)
|
||||
if afterRealseDismissing != self.afterReleaseDismissing {
|
||||
self.afterReleaseDismissing = afterRealseDismissing
|
||||
if self.hapticMoments.contains(.willDismissIfRelease) {
|
||||
self.feedbackGenerator.impactOccurred()
|
||||
if !self.workConfirmation {
|
||||
if self.hapticMoments.contains(.willDismissIfRelease) {
|
||||
self.feedbackGenerator.impactOccurred()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,8 +529,6 @@ extension SPStorkPresentationController {
|
||||
private func updateLayoutIndicator() {
|
||||
self.indicatorView.style = .line
|
||||
self.indicatorView.sizeToFit()
|
||||
//self.indicatorView.frame.origin.y = 12
|
||||
//self.indicatorView.center.x = presentedView.frame.width / 2
|
||||
}
|
||||
|
||||
private func updateLayoutCloseButton() {
|
||||
|
||||
@@ -34,6 +34,7 @@ public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTrans
|
||||
public var cornerRadius: CGFloat = 10
|
||||
public var hapticMoments: [SPStorkHapticMoments] = [.willDismissIfRelease]
|
||||
public weak var storkDelegate: SPStorkControllerDelegate? = nil
|
||||
public weak var confirmDelegate: SPStorkControllerConfirmDelegate? = nil
|
||||
|
||||
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
|
||||
let controller = SPStorkPresentationController(presentedViewController: presented, presenting: presenting)
|
||||
@@ -49,6 +50,7 @@ public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTrans
|
||||
controller.hapticMoments = self.hapticMoments
|
||||
controller.transitioningDelegate = self
|
||||
controller.storkDelegate = self.storkDelegate
|
||||
controller.confirmDelegate = self.confirmDelegate
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user