Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 223ec2d2c0 | |||
| a0ca7e9e2a | |||
| f0a1914145 | |||
| 4355f5eb09 | |||
| 6b080f503d | |||
| c23ed83bf0 | |||
| 8b1c77d743 | |||
| 915ef85cff | |||
| dc1050be2a | |||
| 99ba8bf657 | |||
| 2b7e4198cf | |||
| 0969cceac8 | |||
| f349dea851 | |||
| b8e8f8d0ce | |||
| ee5f9ee9de | |||
| 97c8e8aa32 | |||
| 7be93d548e |
BIN
Binary file not shown.
@@ -23,7 +23,7 @@ import UIKit
|
||||
|
||||
public enum SPStorkController {
|
||||
|
||||
static public func scrollViewDidScroll(_ scrollView: UIScrollView, indicatorInset: CGFloat? = nil) {
|
||||
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)
|
||||
@@ -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.dismissWithConfirmation(prepare: nil, 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
|
||||
}
|
||||
@@ -75,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
|
||||
}
|
||||
@@ -82,7 +92,6 @@ public enum SPStorkController {
|
||||
if let presentationController = controller.parent?.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -105,22 +105,40 @@ 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.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.tapCloseButton), for: .touchUpInside)
|
||||
presentedView.addSubview(self.closeButton)
|
||||
|
||||
@@ -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,11 +49,7 @@ class ModalTableViewController: UIViewController {
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
if let storkPresentationController = self.presentationController as? SPStorkPresentationController {
|
||||
storkPresentationController.dismissWithConfirmation(prepare: nil, completion: {
|
||||
print("Custom completion for confirmation. Confirmation is optional.")
|
||||
})
|
||||
}
|
||||
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,7 @@ class ModalViewController: UIViewController {
|
||||
}
|
||||
|
||||
@objc func dismissAction() {
|
||||
if let storkPresentationController = self.presentationController as? SPStorkPresentationController {
|
||||
storkPresentationController.dismissWithConfirmation(prepare: nil, completion: {
|
||||
print("Custom completion for confirmation. Confirmation is optional.")
|
||||
})
|
||||
}
|
||||
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@@ -39,7 +35,7 @@ class ModalViewController: UIViewController {
|
||||
extension ModalViewController: SPStorkControllerConfirmDelegate {
|
||||
|
||||
var needConfirm: Bool {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func confirm(_ completion: @escaping (Bool) -> ()) {
|
||||
|
||||
@@ -17,20 +17,24 @@ If you like the project, do not forget to `put star ★` and follow me on GitHub
|
||||
|
||||
- [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](#confirm)
|
||||
- [Confirm before dismiss](#confirm-before-dismiss)
|
||||
- [Delegate](#delegate)
|
||||
- [Storyboard](#storyboard)
|
||||
- [Sheets in iOS 13](#sheets-in-ios-13)
|
||||
@@ -148,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`:
|
||||
@@ -216,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:
|
||||
|
||||
@@ -275,9 +285,9 @@ 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
|
||||
### Confirm before dismiss
|
||||
|
||||
For confirm closing by swipe, use `SPStorkControllerConfirmDelegate`. Implenet protocol:
|
||||
For confirm closing by swipe, tap around, close button and indicator use `SPStorkControllerConfirmDelegate`. Implenet protocol:
|
||||
|
||||
```swift
|
||||
@objc public protocol SPStorkControllerConfirmDelegate: class {
|
||||
@@ -288,7 +298,15 @@ For confirm closing by swipe, use `SPStorkControllerConfirmDelegate`. Implenet p
|
||||
}
|
||||
```
|
||||
|
||||
and set `confirmDelegate` property to object, which protocol impleneted. Function `confirm` call if `needConfirm` set to `true` and controller try closing by swipe. Pass `isConfirmed` with result. Best options use `UIAlertController` with `.actionSheet` style for confirmation.
|
||||
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
|
||||
|
||||
@@ -341,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.7.2"
|
||||
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 }
|
||||
|
||||
@@ -23,7 +23,7 @@ import UIKit
|
||||
|
||||
public enum SPStorkController {
|
||||
|
||||
static public func scrollViewDidScroll(_ scrollView: UIScrollView, indicatorInset: CGFloat? = nil) {
|
||||
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)
|
||||
@@ -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.dismissWithConfirmation(prepare: nil, 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
|
||||
}
|
||||
@@ -75,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
|
||||
}
|
||||
@@ -82,7 +92,6 @@ public enum SPStorkController {
|
||||
if let presentationController = controller.parent?.presentationController as? SPStorkPresentationController {
|
||||
return presentationController
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -105,22 +105,40 @@ 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.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.tapCloseButton), for: .touchUpInside)
|
||||
presentedView.addSubview(self.closeButton)
|
||||
|
||||
Reference in New Issue
Block a user