21 Commits

Author SHA1 Message Date
Tosin Afolabi b012aecb6b bump version number. 2020-03-30 12:33:24 -07:00
Stephen Sowole 22b4ddd47e [PanModal] Track all dismiss events through panModalPresentable callbacks (#91) 2020-03-25 00:34:58 -07:00
Stephen Sowole 17a8231f20 Update README.md 2020-03-24 17:10:08 -07:00
Stephen Sowole 1819113e97 [ReadMe] Add link to Swift Package Manager 2020-02-27 09:10:21 -08:00
Stephen Sowole 208640e03e [PanModal] Round frame positions for comparison (#83) 2020-02-24 15:20:26 -08:00
Stephen Sowole f02439dc0c [PanModal] Fix issue with incorrect returned bottom offset value (#84) 2020-02-24 15:20:14 -08:00
Kyohei Ito 047415090a Fix Background dimming animation broken (#77) 2020-02-24 14:02:45 -08:00
Abdullah Selek 1e7c0534fc Use keyPath to read UIApplication.shared. (#81) 2020-02-12 13:02:33 -06:00
Tosin Afolabi 7f07cdff27 Initial SPM Support 2019-11-11 10:52:18 -08:00
Nikita Nikitsky 45f8dfcf19 Add support for Swift Package Manager (#55) 2019-11-11 10:49:59 -08:00
Tosin Afolabi 5d2b0977bd Swift 5.0 Support 2019-11-11 10:26:03 -08:00
Simonas Daniliauskas a792f46e3d Add customizable drag indicator background color (#62)
* Add ability to customize drag indicator background color

* Add default dragIndicatorBackgroundColor test

* update PR according to comments
2019-10-28 12:57:36 -07:00
Guillian Balisi d6b4ba3d05 Make PanModalPresentationController subclassable (#60) 2019-10-22 11:10:43 -07:00
Scott Campbell 5c1d8c49a7 Add allowTapToDismiss to PanModalPresentable (#58) 2019-10-09 13:06:51 -07:00
Stephen Sowole af264ebb0d [PanModal] Fix handleScrollViewTopBounce calls (#56)
* [PanModal] Fix calls to handleScrollViewTopBounce if scrollView is not decelerating

* [PanModal] Replace `setContentOffset` with more generic `performUpdates`

* [PanModal] Add appropriate comments
2019-10-09 13:06:12 -07:00
Santos 9d73db3919 PanModal Portrait to Landscape Issue (#53)
* Fix issue where transitioning from portrait to landscape would cause a PanModal's view to disappear if its height was short

* improve transitioning to landscape fix
2019-10-04 11:45:16 -07:00
Nikita Nikitsky 6b1edd1dfb Added the ability to select a color for the background of the pan modal container (#54) 2019-10-01 15:53:39 -07:00
Stephen Sowole 9134d20032 [PanModal] Fix unbalanced calls to appearance (#52)
* [PanModal] Use init instead of viewDidLoad in NavigationController

* [PanModal] Remove unbalanced calls to viewWillAppear/viewWillDisappear
2019-09-30 14:02:59 -07:00
Shohei Yokoyama 0c6f9ff040 Notify delegate method after the pan modal is dismissed (#44)
* Notify delegate method after the pan modal is dismissed

* Rename panModalDismissCompleted panModalDidDismiss
2019-09-22 15:25:41 -07:00
liang 12ac36646f Update README.md (#43)
Add summary and blog post link
2019-08-23 10:40:20 -07:00
Tosin Afolabi f9fedcb597 Further fix for horizontal sliding + version bump 2019-06-12 20:50:49 -07:00
21 changed files with 207 additions and 94 deletions
+22
View File
@@ -0,0 +1,22 @@
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "PanModal",
platforms: [.iOS(.v10)],
products: [
.library(
name: "PanModal",
targets: ["PanModal"]),
],
dependencies: [],
targets: [
.target(
name: "PanModal",
dependencies: [],
path: "PanModal")
],
swiftLanguageVersions: [.version("5.0")]
)
+2 -2
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'PanModal'
s.version = '1.2.3'
s.version = '1.2.7'
s.summary = 'PanModal is an elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.'
# This description is used to generate tags and improve search results.
@@ -24,6 +24,6 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/slackhq/PanModal.git', :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/slackhq'
s.ios.deployment_target = '10.0'
s.swift_version = '4.2'
s.swift_version = '5.0'
s.source_files = 'PanModal/**/*.{swift,h,m}'
end
+2
View File
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -36,3 +37,4 @@ struct PanModalAnimator {
completion: completion)
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -72,7 +73,6 @@ public class PanModalPresentationAnimator: NSObject {
// Calls viewWillAppear and viewWillDisappear
fromVC.beginAppearanceTransition(false, animated: true)
toVC.beginAppearanceTransition(true, animated: true)
// Presents the view in shortForm position, initially
let yPos: CGFloat = presentable?.shortFormYPos ?? 0.0
@@ -94,7 +94,6 @@ public class PanModalPresentationAnimator: NSObject {
}, config: presentable) { [weak self] didComplete in
// Calls viewDidAppear and viewDidDisappear
fromVC.endAppearanceTransition()
toVC.endAppearanceTransition()
transitionContext.completeTransition(didComplete)
self?.feedbackGenerator = nil
}
@@ -111,7 +110,6 @@ public class PanModalPresentationAnimator: NSObject {
else { return }
// Calls viewWillAppear and viewWillDisappear
fromVC.beginAppearanceTransition(false, animated: true)
toVC.beginAppearanceTransition(true, animated: true)
let presentable = panModalLayoutType(from: transitionContext)
@@ -122,7 +120,6 @@ public class PanModalPresentationAnimator: NSObject {
}, config: presentable) { didComplete in
fromVC.view.removeFromSuperview()
// Calls viewDidAppear and viewDidDisappear
fromVC.endAppearanceTransition()
toVC.endAppearanceTransition()
transitionContext.completeTransition(didComplete)
}
@@ -172,3 +169,4 @@ extension PanModalPresentationAnimator: UIViewControllerAnimatedTransitioning {
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -22,7 +23,7 @@ import UIKit
By conforming to the PanModalPresentable protocol & overriding values
the presented view can define its layout configuration & presentation.
*/
public class PanModalPresentationController: UIPresentationController {
open class PanModalPresentationController: UIPresentationController {
/**
Enum representing the possible presentation states
@@ -105,13 +106,15 @@ public class PanModalPresentationController: UIPresentationController {
*/
private lazy var backgroundView: DimmedView = {
let view: DimmedView
if let alpha = presentable?.backgroundAlpha {
view = DimmedView(dimAlpha: alpha)
if let color = presentable?.panModalBackgroundColor {
view = DimmedView(dimColor: color)
} else {
view = DimmedView()
}
view.didTap = { [weak self] _ in
self?.dismissPresentedViewController()
if self?.presentable?.allowsTapToDismiss == true {
self?.presentedViewController.dismiss(animated: true)
}
}
return view
}()
@@ -131,7 +134,7 @@ public class PanModalPresentationController: UIPresentationController {
*/
private lazy var dragIndicatorView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
view.backgroundColor = presentable?.dragIndicatorBackgroundColor
view.layer.cornerRadius = Constants.dragIndicatorSize.height / 2.0
return view
}()
@@ -189,7 +192,14 @@ public class PanModalPresentationController: UIPresentationController {
})
}
override public func presentationTransitionDidEnd(_ completed: Bool) {
if completed { return }
backgroundView.removeFromSuperview()
}
override public func dismissalTransitionWillBegin() {
presentable?.panModalWillDismiss()
guard let coordinator = presentedViewController.transitionCoordinator else {
backgroundView.dimState = .off
@@ -207,10 +217,10 @@ public class PanModalPresentationController: UIPresentationController {
})
}
override public func presentationTransitionDidEnd(_ completed: Bool) {
if completed { return }
backgroundView.removeFromSuperview()
override public func dismissalTransitionDidEnd(_ completed: Bool) {
if !completed { return }
presentable?.panModalDidDismiss()
}
/**
@@ -226,7 +236,6 @@ public class PanModalPresentationController: UIPresentationController {
else { return }
self.adjustPresentedViewFrame()
if presentable.shouldRoundTopCorners {
self.addRoundedCorners(to: self.presentedView)
}
@@ -259,35 +268,27 @@ public extension PanModalPresentationController {
}
/**
Set the content offset of the scroll view
Operations on the scroll view, such as content height changes,
or when inserting/deleting rows can cause the pan modal to jump,
caused by the pan modal responding to content offset changes.
Due to content offset observation, its not possible to programmatically
set the content offset directly on the scroll view while in the short form.
This method pauses the content offset KVO, performs the content offset change
and then resumes content offset observation.
To avoid this, you can call this method to perform scroll view updates,
with scroll observation temporarily disabled.
*/
func setContentOffset(offset: CGPoint) {
func performUpdates(_ updates: () -> Void) {
guard let scrollView = presentable?.panScrollable
else { return }
/**
Invalidate scroll view observer
to prevent its overriding the content offset change
*/
// Pause scroll observer
scrollObserver?.invalidate()
scrollObserver = nil
/**
Set scroll view offset & track scrolling
*/
scrollView.setContentOffset(offset, animated:false)
trackScrolling(scrollView)
// Perform updates
updates()
/**
Add the scroll view observer
*/
// Resume scroll observer
trackScrolling(scrollView)
observe(scrollView: scrollView)
}
@@ -317,7 +318,7 @@ private extension PanModalPresentationController {
var isPresentedViewAnchored: Bool {
if !isPresentedViewAnimating
&& extendsPanScrolling
&& presentedView.frame.minY <= anchoredYPosition {
&& presentedView.frame.minY.rounded() <= anchoredYPosition.rounded() {
return true
}
@@ -367,7 +368,16 @@ private extension PanModalPresentationController {
else { return }
let adjustedSize = CGSize(width: frame.size.width, height: frame.size.height - anchoredYPosition)
let panFrame = panContainerView.frame
panContainerView.frame.size = frame.size
if ![shortFormYPosition, longFormYPosition].contains(panFrame.origin.y) {
// if the container is already in the correct position, no need to adjust positioning
// (rotations & size changes cause positioning to be out of sync)
let yPosition = panFrame.origin.y - panFrame.height + frame.height
presentedView.frame.origin.y = max(yPosition, anchoredYPosition)
}
panContainerView.frame.origin.x = frame.origin.x
presentedViewController.view.frame = CGRect(origin: .zero, size: adjustedSize)
}
@@ -513,7 +523,7 @@ private extension PanModalPresentationController {
transition(to: .shortForm)
} else {
dismissPresentedViewController()
presentedViewController.dismiss(animated: true)
}
} else {
@@ -531,7 +541,7 @@ private extension PanModalPresentationController {
transition(to: .shortForm)
} else {
dismissPresentedViewController()
presentedViewController.dismiss(animated: true)
}
}
}
@@ -670,14 +680,6 @@ private extension PanModalPresentationController {
else { return number }
return nearestVal
}
/**
Dismiss presented view
*/
func dismissPresentedViewController() {
presentable?.panModalWillDismiss()
presentedViewController.dismiss(animated: true, completion: nil)
}
}
// MARK: - UIScrollView Observer
@@ -782,7 +784,7 @@ private extension PanModalPresentationController {
*/
func handleScrollViewTopBounce(scrollView: UIScrollView, change: NSKeyValueObservedChange<CGPoint>) {
guard let oldYValue = change.oldValue?.y
guard let oldYValue = change.oldValue?.y, scrollView.isDecelerating
else { return }
let yOffset = scrollView.contentOffset.y
@@ -822,11 +824,11 @@ extension PanModalPresentationController: UIGestureRecognizerDelegate {
}
/**
Allow simultaneous gesture recognizers only when the other gesture recognizer
is a pan gesture recognizer
Allow simultaneous gesture recognizers only when the other gesture recognizer's view
is the pan scrollable view
*/
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return otherGestureRecognizer == panGestureRecognizer
return otherGestureRecognizer.view == presentable?.panScrollable
}
}
@@ -887,3 +889,4 @@ private extension UIScrollView {
return isDragging && !isDecelerating || isTracking
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -77,3 +78,4 @@ extension PanModalPresentationDelegate: UIAdaptivePresentationControllerDelegate
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -40,3 +41,4 @@ public enum PanModalHeight: Equatable {
*/
case intrinsicHeight
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2018 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -46,8 +47,12 @@ public extension PanModalPresentable where Self: UIViewController {
return [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState]
}
var backgroundAlpha: CGFloat {
return 0.7
var panModalBackgroundColor: UIColor {
return UIColor.black.withAlphaComponent(0.7)
}
var dragIndicatorBackgroundColor: UIColor {
return UIColor.lightGray
}
var scrollIndicatorInsets: UIEdgeInsets {
@@ -72,6 +77,10 @@ public extension PanModalPresentable where Self: UIViewController {
return true
}
var allowsTapToDismiss: Bool {
return true
}
var isUserInteractionEnabled: Bool {
return true
}
@@ -112,4 +121,8 @@ public extension PanModalPresentable where Self: UIViewController {
}
func panModalDidDismiss() {
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2018 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -26,7 +27,11 @@ extension PanModalPresentable where Self: UIViewController {
Gives us the safe area inset from the top.
*/
var topLayoutOffset: CGFloat {
return UIApplication.shared.keyWindow?.rootViewController?.topLayoutGuide.length ?? 0
guard let rootVC = rootViewController
else { return 0}
if #available(iOS 11.0, *) { return rootVC.view.safeAreaInsets.top } else { return rootVC.topLayoutGuide.length }
}
/**
@@ -34,7 +39,11 @@ extension PanModalPresentable where Self: UIViewController {
Gives us the safe area inset from the bottom.
*/
var bottomLayoutOffset: CGFloat {
return UIApplication.shared.keyWindow?.rootViewController?.bottomLayoutGuide.length ?? 0
guard let rootVC = rootViewController
else { return 0}
if #available(iOS 11.0, *) { return rootVC.view.safeAreaInsets.bottom } else { return rootVC.bottomLayoutGuide.length }
}
/**
@@ -99,4 +108,13 @@ extension PanModalPresentable where Self: UIViewController {
}
}
private var rootViewController: UIViewController? {
guard let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication
else { return nil }
return application.keyWindow?.rootViewController
}
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2018 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -29,16 +30,6 @@ public extension PanModalPresentable where Self: UIViewController {
presentedVC?.transition(to: state)
}
/**
Programmatically set the content offset of the pan scrollable.
This is required to use while in the short form presentation state,
as due to content offset observation, setting the content offset directly would fail
*/
func panModalSetContentOffset(offset: CGPoint) {
presentedVC?.setContentOffset(offset: offset)
}
/**
A function wrapper over the `setNeedsLayoutUpdate()`
function in the PanModalPresentationController.
@@ -49,6 +40,16 @@ public extension PanModalPresentable where Self: UIViewController {
presentedVC?.setNeedsLayoutUpdate()
}
/**
Operations on the scroll view, such as content height changes, or when inserting/deleting rows can cause the pan modal to jump,
caused by the pan modal responding to content offset changes.
To avoid this, you can call this method to perform scroll view updates, with scroll observation temporarily disabled.
*/
func panModalPerformUpdates(_ updates: () -> Void) {
presentedVC?.performUpdates(updates)
}
/**
A function wrapper over the animate function in PanModalAnimator.
@@ -59,3 +60,4 @@ public extension PanModalPresentable where Self: UIViewController {
}
}
#endif
+26 -4
View File
@@ -5,6 +5,7 @@
// Copyright © 2017 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -86,13 +87,20 @@ public protocol PanModalPresentable: AnyObject {
var transitionAnimationOptions: UIView.AnimationOptions { get }
/**
The background view alpha.
The background view color.
- Note: This is only utilized at the very start of the transition.
Default Value is 0.7.
*/
var backgroundAlpha: CGFloat { get }
Default Value is black with alpha component 0.7.
*/
var panModalBackgroundColor: UIColor { get }
/**
The drag indicator view color.
Default value is light gray.
*/
var dragIndicatorBackgroundColor: UIColor { get }
/**
We configure the panScrollable's scrollIndicatorInsets interally so override this value
@@ -127,6 +135,13 @@ public protocol PanModalPresentable: AnyObject {
*/
var allowsDragToDismiss: Bool { get }
/**
A flag to determine if dismissal should be initiated when tapping on the dimmed background view.
Default value is true.
*/
var allowsTapToDismiss: Bool { get }
/**
A flag to toggle user interactions on the container view.
@@ -212,4 +227,11 @@ public protocol PanModalPresentable: AnyObject {
*/
func panModalWillDismiss()
/**
Notifies the delegate after the pan modal is dismissed.
Default value is an empty implementation.
*/
func panModalDidDismiss()
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -31,3 +32,4 @@ protocol PanModalPresenter: AnyObject {
func presentPanModal(_ viewControllerToPresent: PanModalPresentable.LayoutType, sourceView: UIView?, sourceRect: CGRect)
}
#endif
@@ -5,6 +5,7 @@
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -58,3 +59,4 @@ extension UIViewController: PanModalPresenter {
}
}
#endif
+6 -8
View File
@@ -5,6 +5,7 @@
// Copyright © 2017 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -31,12 +32,11 @@ public class DimmedView: UIView {
didSet {
switch dimState {
case .max:
alpha = dimAlpha
alpha = 1.0
case .off:
alpha = 0.0
case .percent(let percentage):
let val = max(0.0, min(1.0, percentage))
alpha = dimAlpha * val
alpha = max(0.0, min(1.0, percentage))
}
}
}
@@ -53,15 +53,12 @@ public class DimmedView: UIView {
return UITapGestureRecognizer(target: self, action: #selector(didTapView))
}()
private let dimAlpha: CGFloat
// MARK: - Initializers
init(dimAlpha: CGFloat = 0.7) {
self.dimAlpha = dimAlpha
init(dimColor: UIColor = UIColor.black.withAlphaComponent(0.7)) {
super.init(frame: .zero)
alpha = 0.0
backgroundColor = .black
backgroundColor = dimColor
addGestureRecognizer(tapGesture)
}
@@ -76,3 +73,4 @@ public class DimmedView: UIView {
}
}
#endif
+2
View File
@@ -5,6 +5,7 @@
// Copyright © 2018 Tiny Speck, Inc. All rights reserved.
//
#if os(iOS)
import UIKit
/**
@@ -40,3 +41,4 @@ extension UIView {
}
}
#endif
+8 -6
View File
@@ -629,7 +629,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.slack.PanModal;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -658,7 +658,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.slack.PanModal;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -679,7 +679,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = slack.PanModalTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModalDemo.app/PanModalDemo";
};
@@ -699,7 +699,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = slack.PanModalTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModalDemo.app/PanModalDemo";
};
@@ -763,6 +763,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -817,6 +818,7 @@
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -837,7 +839,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.PanModal;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@@ -858,7 +860,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.PanModal;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
+19 -2
View File
@@ -1,10 +1,13 @@
### PanModal is an elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.
<p align="center">
<img src="https://github.com/slackhq/PanModal/raw/master/Screenshots/panModal.gif" width="30%" height="30%" alt="Screenshot Preview" />
</p>
<p align="center">
<img src="https://img.shields.io/badge/Platform-iOS_10+-green.svg" alt="Platform: iOS 10.0+" />
<a href="https://developer.apple.com/swift" target="_blank"><img src="https://img.shields.io/badge/Language-Swift_4-blueviolet.svg" alt="Language: Swift 4" /></a>
<a href="https://developer.apple.com/swift" target="_blank"><img src="https://img.shields.io/badge/Language-Swift_5-blueviolet.svg" alt="Language: Swift 5" /></a>
<a href="https://cocoapods.org/pods/PanModal" target="_blank"><img src="https://img.shields.io/badge/CocoaPods-v1.0-red.svg" alt="CocoaPods compatible" /></a>
<a href="https://github.com/Carthage/Carthage" target="_blank"><img src="https://img.shields.io/badge/Carthage-compatible-blue.svg" alt="Carthage compatible" /></a>
<img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT" />
@@ -21,6 +24,12 @@
• <a href="#license">License</a>
</p>
<p align="center">
Read our <a href="https://slack.engineering/panmodal-better-support-for-thumb-accessibility-on-slack-mobile-52b2a7596031" target="_blank">blog</a> on how Slack is getting more :thumbsup: with PanModal
Swift 4.2 support can be found on the `Swift4.2` branch.
</p>
## Features
* Supports any type of `UIViewController`
@@ -45,6 +54,14 @@ pod 'PanModal'
github "slackhq/PanModal"
```
* <a href="https://swift.org/package-manager/" target="_blank">Swift Package Manager</a>:
```swift
dependencies: [
.package(url: "https://github.com/slackhq/PanModal.git", .exact("1.2.6")),
],
```
## Usage
PanModal was designed to be used effortlessly. Simply call `presentPanModal` in the same way you would expect to present a `UIViewController`
@@ -130,7 +147,7 @@ We will only be fixing critical bugs, thus, for any non-critical issues or featu
## Authors
[Stephen Sowole](https://github.com/tun57) • [Tosin Afolabi](https://github.com/tosinaf)
[Stephen Sowole](https://github.com/ste57) • [Tosin Afolabi](https://github.com/tosinaf)
## License
@@ -59,8 +59,8 @@ class TransientAlertViewController: AlertViewController {
return true
}
override var backgroundAlpha: CGFloat {
return 0.0
override var panModalBackgroundColor: UIColor {
return .clear
}
override var isUserInteractionEnabled: Bool {
@@ -46,8 +46,8 @@ class AlertViewController: UIViewController, PanModalPresentable {
return shortFormHeight
}
var backgroundAlpha: CGFloat {
return 0.1
var panModalBackgroundColor: UIColor {
return UIColor.black.withAlphaComponent(0.1)
}
var shouldRoundTopCorners: Bool {
@@ -12,13 +12,17 @@ class NavigationController: UINavigationController, PanModalPresentable {
private let navGroups = NavUserGroups()
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
init() {
super.init(nibName: nil, bundle: nil)
viewControllers = [navGroups]
}
override func viewDidLoad() {
super.viewDidLoad()
pushViewController(navGroups, animated: false)
required init?(coder aDecoder: NSCoder) {
fatalError()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func popViewController(animated: Bool) -> UIViewController? {
+3 -1
View File
@@ -48,11 +48,13 @@ class PanModalTests: XCTestCase {
XCTAssertEqual(vc.shortFormHeight, PanModalHeight.maxHeight)
XCTAssertEqual(vc.longFormHeight, PanModalHeight.maxHeight)
XCTAssertEqual(vc.springDamping, 0.8)
XCTAssertEqual(vc.backgroundAlpha, 0.7)
XCTAssertEqual(vc.panModalBackgroundColor, UIColor.black.withAlphaComponent(0.7))
XCTAssertEqual(vc.dragIndicatorBackgroundColor, UIColor.lightGray)
XCTAssertEqual(vc.scrollIndicatorInsets, .zero)
XCTAssertEqual(vc.anchorModalToLongForm, true)
XCTAssertEqual(vc.allowsExtendedPanScrolling, false)
XCTAssertEqual(vc.allowsDragToDismiss, true)
XCTAssertEqual(vc.allowsTapToDismiss, true)
XCTAssertEqual(vc.isUserInteractionEnabled, true)
XCTAssertEqual(vc.isHapticFeedbackEnabled, true)
XCTAssertEqual(vc.shouldRoundTopCorners, false)