51 Commits

Author SHA1 Message Date
Tosin Afolabi 4206308afd Version Bump to 1.2.3 2019-06-08 13:56:00 -07:00
Tosin Afolabi 0234d82979 Fix Horizonal Sliding Issues by only recogizing simultaneous gestures if the other gesture its the pan gesture (#32) 2019-06-08 13:52:59 -07:00
Giulio b0fb9e7eed Improve Swift syntax (#25)
* Replace init-ializable struct with enums

* Add AnyObject requirement to protocols

* Hide init?(coder aDecoder: NSCoder) func

* Improve Swift syntax

* Revert "Replace init-ializable struct with enums"

This reverts commit 1be2e8c23c.
2019-05-17 11:42:21 -05:00
tun57 a9edeb1d71 Update "Full Screen" mode in Sample App 2019-05-11 18:38:12 -07:00
tun57 b8f7e613ec Update PanModalTests.swift 2019-05-11 18:34:10 -07:00
tun57 8a662e829b Update PanModalPresentationAnimator.swift 2019-05-11 18:34:04 -07:00
tun57 0b2152f878 Set default transition values on PanModalPresentable 2019-05-11 18:32:07 -07:00
tun57 13251e1db7 Update PanModalAnimator.swift 2019-05-11 18:31:26 -07:00
tun57 da4c94e47e Remove redundant public accessors 2019-05-11 18:30:53 -07:00
tun57 0d999396a5 Add transitionDuration & transitionAnimationOptions to PanModalPresentatable 2019-05-11 18:29:19 -07:00
tun57 8e39823698 Default PanModalPresenter to internal 2019-05-11 18:26:20 -07:00
Stephen Sowole 457ebaed94 Add "Full Screen" mode to Sample app 2019-05-09 15:49:05 -07:00
Stephen Sowole 32e4a6fa24 No need to dismiss during size class change 2019-05-09 15:20:27 -07:00
Stephen Sowole 2736468072 Update UserGroupViewController.swift 2019-05-07 11:38:05 -07:00
Stephen Sowole c76ae09bc9 Update SampleViewController.swift 2019-05-02 16:47:02 -07:00
Stephen Sowole 12d6380d07 Add FullScreenViewController 2019-05-02 16:46:55 -07:00
Stephen Sowole 77c9f6f806 Group BasicViewController 2019-05-02 16:46:42 -07:00
Rune Madsen 964d444ff6 Adding functionality for UIViewController appearance callback forwarding (#21) 2019-04-23 22:27:37 -05:00
Stephen Sowole 9456969502 Limit when we adjust container view frame 2019-04-04 10:17:07 -07:00
Stephen Sowole 0750bd980e Update PanModalPresentationController.swift (#15) 2019-04-02 14:49:45 -07:00
Tosin Afolabi 056351af4b Update PanModal.podspec 2019-04-02 07:17:25 -07:00
Eude Lesperance dab02d34c0 Correct some docs typos (#11) 2019-03-24 20:58:33 -07:00
Stephen Sowole 96591ef52c Update PanModalPresentationController.swift 2019-03-22 14:10:06 -04:00
Tosin Afolabi 1defbf2a47 Update PanModal.podspec 2019-03-20 14:09:32 -07:00
Tosin Afolabi b58552279e Update PanModal.podspec 2019-03-20 14:09:01 -07:00
Stephen Sowole ef7f00dab7 Replace isPanScrollEnabled with shouldRespond(to .. (#10)
* Replace `isPanScrollEnabled` with `shouldRespond(to ..`

* Update PanModalPresentable+Defaults.swift
2019-03-20 13:58:17 -07:00
Stephen Sowole d70dce231f Documentation nits. 2019-03-19 18:56:55 -07:00
Abdurahim Jauzee 5baac6732e [Trivial] Exclude Info.plist from Compile Sources (#8) 2019-03-18 09:47:12 -07:00
Tosin Afolabi 1d8b218056 minor nits. 2019-03-14 13:56:25 -07:00
Tosin Afolabi ae78bd6f64 Minor nits. 2019-03-14 13:56:15 -07:00
Tosin Afolabi 2b3029333e Fix Tests Scheme. 2019-03-14 13:48:38 -07:00
Tosin Afolabi f71fa70302 Merge pull request #5 from Marcocanc/intrinsic-height
Add Intrinsic Height to PanModalHeight
2019-03-14 13:44:47 -07:00
Tosin Afolabi 6438b952cc Merge pull request #6 from Marcocanc/corner-radius
Add configurable cornerRadius
2019-03-14 13:43:55 -07:00
Marco Cancellieri a7d7033ef0 nit 2019-03-14 21:40:13 +01:00
Marco Cancellieri 3f3124ae37 pr comment 2019-03-14 21:38:02 +01:00
Marco Cancellieri 0da0a44c4a pr comments 2019-03-14 21:35:20 +01:00
Tosin Afolabi 88dc3324f6 Merge pull request #4 from Marcocanc/status-bar-appearance
Add support for changing status bar appearance
2019-03-14 13:30:26 -07:00
Marco Cancellieri d0b094292f Add configurable cornerRadius 2019-03-14 19:23:45 +01:00
Tosin Afolabi 15f39a1929 Update CONTRIBUTING.md 2019-03-14 11:04:31 -07:00
Tosin Afolabi f5379a1051 Merge pull request #2 from Marcocanc/carthage-deployment-target
Set Deployment Target to 10.0 for Carthage
2019-03-14 10:36:52 -07:00
Marco Cancellieri 21bcb6f268 Add Intrinsic Height 2019-03-14 18:17:29 +01:00
Marco Cancellieri f7cb63caaa Add support for changing status bar appearance 2019-03-14 16:17:49 +01:00
Marco Cancellieri c83516694f Set Deployment Target to 10.0 2019-03-14 13:41:55 +01:00
Tosin Afolabi d9f37de98c Update Scheme. 2019-03-13 16:00:53 -07:00
Tosin Afolabi b1c2d82029 Progress on Carthage Support. 2019-03-13 15:54:44 -07:00
Tosin Afolabi 68e21c3988 Add Project Scheme. 2019-03-13 15:25:13 -07:00
Tosin Afolabi a8408ebb80 Update podspec. 2019-03-13 15:02:48 -07:00
Tosin Afolabi 714d1bf03f Update version number. 2019-03-13 15:02:17 -07:00
Tosin Afolabi 444b342748 Update swift version in Podspec. 2019-03-13 14:55:40 -07:00
Tosin Afolabi 7b3c3d210c Update Podspec version 2019-03-13 14:46:42 -07:00
Tosin Afolabi f58cda2863 update podspec. 2019-03-13 14:42:09 -07:00
27 changed files with 777 additions and 130 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ Issues labelled `good first contribution`.
For your contribution to be accepted:
- [x] You must have signed the [Contributor License Agreement (CLA)](https://cla-assistant.io/PanModal).
- [x] You must have signed the [Contributor License Agreement (CLA)](https://cla-assistant.io/slackHQ/PanModal).
- [x] The test suite must be complete and pass.
- [x] The changes must be approved by code review.
- [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number.
+5 -9
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'PanModal'
s.version = '1.0'
s.version = '1.2.3'
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.
@@ -17,17 +17,13 @@ Pod::Spec.new do |s|
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
PanModal is an elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.
DESC
s.description = 'PanModal is an elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.'
s.homepage = 'https://github.com/slackhq/PanModal'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'slack' => 'opensource@slack.com' }
s.source = { :git => 'https://github.com/slackhq/PanModal.git', :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/slackhq
s.social_media_url = 'https://twitter.com/slackhq'
s.ios.deployment_target = '10.0'
s.source_files = 'PanModal/**/*'
s.swift_version = '4.2'
s.source_files = 'PanModal/**/*.{swift,h,m}'
end
+8 -4
View File
@@ -16,18 +16,22 @@ struct PanModalAnimator {
Constant Animation Properties
*/
struct Constants {
static let transitionDuration: TimeInterval = 0.5
static let defaultTransitionDuration: TimeInterval = 0.5
}
static func animate(_ animations: @escaping PanModalPresentable.AnimationBlockType,
config: PanModalPresentable?,
_ completion: PanModalPresentable.AnimationCompletionType? = nil) {
UIView.animate(withDuration: Constants.transitionDuration,
let transitionDuration = config?.transitionDuration ?? Constants.defaultTransitionDuration
let springDamping = config?.springDamping ?? 1.0
let animationOptions = config?.transitionAnimationOptions ?? []
UIView.animate(withDuration: transitionDuration,
delay: 0,
usingSpringWithDamping: config?.springDamping ?? 1.0,
usingSpringWithDamping: springDamping,
initialSpringVelocity: 0,
options: [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState],
options: animationOptions,
animations: animations,
completion: completion)
}
@@ -63,11 +63,17 @@ public class PanModalPresentationAnimator: NSObject {
*/
private func animatePresentation(transitionContext: UIViewControllerContextTransitioning) {
guard let toVC = transitionContext.viewController(forKey: .to)
guard
let toVC = transitionContext.viewController(forKey: .to),
let fromVC = transitionContext.viewController(forKey: .from)
else { return }
let presentable = toVC as? PanModalPresentable.LayoutType
let presentable = panModalLayoutType(from: transitionContext)
// 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
@@ -86,6 +92,9 @@ public class PanModalPresentationAnimator: NSObject {
PanModalAnimator.animate({
panView.frame.origin.y = yPos
}, config: presentable) { [weak self] didComplete in
// Calls viewDidAppear and viewDidDisappear
fromVC.endAppearanceTransition()
toVC.endAppearanceTransition()
transitionContext.completeTransition(didComplete)
self?.feedbackGenerator = nil
}
@@ -96,20 +105,41 @@ public class PanModalPresentationAnimator: NSObject {
*/
private func animateDismissal(transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from)
guard
let toVC = transitionContext.viewController(forKey: .to),
let fromVC = transitionContext.viewController(forKey: .from)
else { return }
let presentable = fromVC as? PanModalPresentable.LayoutType
// Calls viewWillAppear and viewWillDisappear
fromVC.beginAppearanceTransition(false, animated: true)
toVC.beginAppearanceTransition(true, animated: true)
let presentable = panModalLayoutType(from: transitionContext)
let panView: UIView = transitionContext.containerView.panContainerView ?? fromVC.view
PanModalAnimator.animate({
panView.frame.origin.y = transitionContext.containerView.frame.height
}, config: presentable) { didComplete in
fromVC.view.removeFromSuperview()
// Calls viewDidAppear and viewDidDisappear
fromVC.endAppearanceTransition()
toVC.endAppearanceTransition()
transitionContext.completeTransition(didComplete)
}
}
/**
Extracts the PanModal from the transition context, if it exists
*/
private func panModalLayoutType(from context: UIViewControllerContextTransitioning) -> PanModalPresentable.LayoutType? {
switch transitionStyle {
case .presentation:
return context.viewController(forKey: .to) as? PanModalPresentable.LayoutType
case .dismissal:
return context.viewController(forKey: .from) as? PanModalPresentable.LayoutType
}
}
}
// MARK: - UIViewControllerAnimatedTransitioning Delegate
@@ -120,11 +150,17 @@ extension PanModalPresentationAnimator: UIViewControllerAnimatedTransitioning {
Returns the transition duration
*/
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return PanModalAnimator.Constants.transitionDuration
guard
let context = transitionContext,
let presentable = panModalLayoutType(from: context)
else { return PanModalAnimator.Constants.defaultTransitionDuration }
return presentable.transitionDuration
}
/**
Perfroms the appropriate animation based on the transition style
Performs the appropriate animation based on the transition style
*/
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
switch transitionStyle {
@@ -36,7 +36,6 @@ public class PanModalPresentationController: UIPresentationController {
Constants
*/
struct Constants {
static let cornerRadius = CGFloat(8.0)
static let indicatorYOffset = CGFloat(8.0)
static let snapMovementSensitivity = CGFloat(0.7)
static let dragIndicatorSize = CGSize(width: 36.0, height: 5.0)
@@ -186,6 +185,7 @@ public class PanModalPresentationController: UIPresentationController {
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.backgroundView.dimState = .max
self?.presentedViewController.setNeedsStatusBarAppearanceUpdate()
})
}
@@ -198,11 +198,12 @@ public class PanModalPresentationController: UIPresentationController {
/**
Drag indicator is drawn outside of view bounds
so hiding it on view dismiss means avoids visual bugs
so hiding it on view dismiss means avoiding visual bugs
*/
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.dragIndicatorView.alpha = 0.0
self?.backgroundView.dimState = .off
self?.presentingViewController.setNeedsStatusBarAppearanceUpdate()
})
}
@@ -212,6 +213,26 @@ public class PanModalPresentationController: UIPresentationController {
backgroundView.removeFromSuperview()
}
/**
Update presented view size in response to size class changes
*/
override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [weak self] _ in
guard
let self = self,
let presentable = self.presentable
else { return }
self.adjustPresentedViewFrame()
if presentable.shouldRoundTopCorners {
self.addRoundedCorners(to: self.presentedView)
}
})
}
}
// MARK: - Public Methods
@@ -219,10 +240,10 @@ public class PanModalPresentationController: UIPresentationController {
public extension PanModalPresentationController {
/**
Tranisition the PanModalPresentationController
Transition the PanModalPresentationController
to the given presentation state
*/
public func transition(to state: PresentationState) {
func transition(to state: PresentationState) {
guard presentable?.shouldTransition(to: state) == true
else { return }
@@ -243,10 +264,10 @@ public extension PanModalPresentationController {
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 chnage
This method pauses the content offset KVO, performs the content offset change
and then resumes content offset observation.
*/
public func setContentOffset(offset: CGPoint) {
func setContentOffset(offset: CGPoint) {
guard let scrollView = presentable?.panScrollable
else { return }
@@ -272,12 +293,12 @@ public extension PanModalPresentationController {
/**
Updates the PanModalPresentationController layout
based on values in the PanModalPresentabls
based on values in the PanModalPresentable
- Note: This should be called whenever any
pan modal presentable value changes after the initial presentation
*/
public func setNeedsLayoutUpdate() {
func setNeedsLayoutUpdate() {
configureViewLayout()
adjustPresentedViewFrame()
observe(scrollView: presentable?.panScrollable)
@@ -341,9 +362,13 @@ private extension PanModalPresentationController {
Reduce height of presentedView so that it sits at the bottom of the screen
*/
func adjustPresentedViewFrame() {
let frame = containerView?.frame ?? .zero
let size = CGSize(width: frame.size.width, height: frame.height - anchoredYPosition)
presentedViewController.view.frame = CGRect(origin: .zero, size: size)
guard let frame = containerView?.frame
else { return }
let adjustedSize = CGSize(width: frame.size.width, height: frame.size.height - anchoredYPosition)
panContainerView.frame.size = frame.size
presentedViewController.view.frame = CGRect(origin: .zero, size: adjustedSize)
}
/**
@@ -383,7 +408,7 @@ private extension PanModalPresentationController {
}
/**
Caluclates & stores the layout anchor points & options
Calculates & stores the layout anchor points & options
*/
func configureViewLayout() {
@@ -413,7 +438,6 @@ private extension PanModalPresentationController {
to avoid visual bugs
*/
scrollView.showsVerticalScrollIndicator = false
scrollView.isScrollEnabled = presentable?.isPanScrollEnabled ?? true
scrollView.scrollIndicatorInsets = presentable?.scrollIndicatorInsets ?? .zero
/**
@@ -443,8 +467,7 @@ private extension PanModalPresentationController {
@objc func didPanOnPresentedView(_ recognizer: UIPanGestureRecognizer) {
guard
presentable?.isPanScrollEnabled == true,
!shouldFail(panGestureRecognizer: recognizer),
shouldRespond(to: recognizer),
let containerView = containerView
else {
recognizer.setTranslation(.zero, in: recognizer.view)
@@ -485,7 +508,7 @@ private extension PanModalPresentationController {
if velocity.y < 0 {
transition(to: .longForm)
} else if (nearestDistance(to: presentedView.frame.minY, inDistances: [longFormYPosition, containerView.bounds.height]) == longFormYPosition
} else if (nearest(to: presentedView.frame.minY, inValues: [longFormYPosition, containerView.bounds.height]) == longFormYPosition
&& presentedView.frame.minY < shortFormYPosition) || presentable?.allowsDragToDismiss == false {
transition(to: .shortForm)
@@ -499,7 +522,7 @@ private extension PanModalPresentationController {
The `containerView.bounds.height` is used to determine
how close the presented view is to the bottom of the screen
*/
let position = nearestDistance(to: presentedView.frame.minY, inDistances: [containerView.bounds.height, shortFormYPosition, longFormYPosition])
let position = nearest(to: presentedView.frame.minY, inValues: [containerView.bounds.height, shortFormYPosition, longFormYPosition])
if position == longFormYPosition {
transition(to: .longForm)
@@ -514,6 +537,26 @@ private extension PanModalPresentationController {
}
}
/**
Determine if the pan modal should respond to the gesture recognizer.
If the pan modal is already being dragged & the delegate returns false, ignore until
the recognizer is back to it's original state (.began)
This is the only time we should be cancelling the pan modal gesture recognizer
*/
func shouldRespond(to panGestureRecognizer: UIPanGestureRecognizer) -> Bool {
guard
presentable?.shouldRespond(to: panGestureRecognizer) == true ||
!(panGestureRecognizer.state == .began || panGestureRecognizer.state == .cancelled)
else {
panGestureRecognizer.isEnabled = false
panGestureRecognizer.isEnabled = true
return false
}
return !shouldFail(panGestureRecognizer: panGestureRecognizer)
}
/**
Communicate intentions to presentable and adjust subviews in containerView
*/
@@ -549,7 +592,7 @@ private extension PanModalPresentationController {
Allow api consumers to override the internal conditions &
decide if the pan gesture recognizer should be prioritized.
This is the only time we should be cancelling a recognizer,
This is the only time we should be cancelling the panScrollable recognizer,
for the purpose of ensuring we're no longer tracking the scrollView
*/
guard !shouldPrioritize(panGestureRecognizer: panGestureRecognizer) else {
@@ -576,7 +619,7 @@ private extension PanModalPresentationController {
*/
func shouldPrioritize(panGestureRecognizer: UIPanGestureRecognizer) -> Bool {
return panGestureRecognizer.state == .began &&
presentable?.shouldPrioritize(panModalGestureRecognizer: panGestureRecognizer) ?? false
presentable?.shouldPrioritize(panModalGestureRecognizer: panGestureRecognizer) == true
}
/**
@@ -616,16 +659,16 @@ private extension PanModalPresentationController {
}
/**
Finds the nearest distance to a given position out of a given array of distance values
Finds the nearest value to a given number out of a given array of float values
- Parameters:
- position: reference postion we are trying to find the closest distance to
- distances: array of positions we would like to compare against
- number: reference float we are trying to find the closest value to
- values: array of floats we would like to compare against
*/
func nearestDistance(to position: CGFloat, inDistances distances: [CGFloat]) -> CGFloat {
guard let nearestDistance = distances.min(by: { abs(position - $0) < abs(position - $1) })
else { return position }
return nearestDistance
func nearest(to number: CGFloat, inValues values: [CGFloat]) -> CGFloat {
guard let nearestVal = values.min(by: { abs(number - $0) < abs(number - $1) })
else { return number }
return nearestVal
}
/**
@@ -783,7 +826,7 @@ extension PanModalPresentationController: UIGestureRecognizerDelegate {
is a pan gesture recognizer
*/
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self)
return otherGestureRecognizer == panGestureRecognizer
}
}
@@ -797,37 +840,23 @@ private extension PanModalPresentationController {
because we render the dragIndicator outside of view bounds
*/
func addRoundedCorners(to view: UIView) {
let radius = presentable?.cornerRadius ?? 0
let path = UIBezierPath(roundedRect: view.bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: radius, height: radius))
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: Constants.cornerRadius))
// 1. Draw left rounded corner
path.addArc(withCenter: CGPoint(x: path.currentPoint.x + Constants.cornerRadius, y: path.currentPoint.y),
radius: Constants.cornerRadius, startAngle: .pi, endAngle: 3.0 * .pi/2.0, clockwise: true)
// 2. Draw around the drag indicator view, if displayed
// Draw around the drag indicator view, if displayed
if presentable?.showDragIndicator == true {
let indicatorLeftEdgeXPos = view.bounds.width/2.0 - Constants.dragIndicatorSize.width/2.0
drawAroundDragIndicator(currentPath: path, indicatorLeftEdgeXPos: indicatorLeftEdgeXPos)
}
// 3. Draw line to right side of presented view, leaving space to draw rounded corner
path.addLine(to: CGPoint(x: view.bounds.width - Constants.cornerRadius, y: path.currentPoint.y))
// 4. Draw right rounded corner
path.addArc(withCenter: CGPoint(x: path.currentPoint.x, y: path.currentPoint.y + Constants.cornerRadius),
radius: Constants.cornerRadius, startAngle: 3.0 * .pi/2.0, endAngle: 0, clockwise: true)
// 5. Draw around final edges of view
path.addLine(to: CGPoint(x: path.currentPoint.x, y: view.bounds.height))
path.addLine(to: CGPoint(x: 0, y: path.currentPoint.y))
// 6. Set path as a mask to display optional drag indicator view & rounded corners
// Set path as a mask to display optional drag indicator view & rounded corners
let mask = CAShapeLayer()
mask.path = path.cgPath
view.layer.mask = mask
// 7. Improve performance by rasterizing the layer
// Improve performance by rasterizing the layer
view.layer.shouldRasterize = true
view.layer.rasterizationScale = UIScreen.main.scale
}
@@ -73,7 +73,6 @@ extension PanModalPresentationDelegate: UIAdaptivePresentationControllerDelegate
Dismisses the presented view controller
*/
public func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
controller.presentedViewController.dismiss(animated: false, completion: nil)
return .none
}
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>
+19
View File
@@ -0,0 +1,19 @@
//
// PanModal.h
// PanModal
//
// Created by Tosin A on 3/13/19.
// Copyright © 2019 Detail. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for PanModal.
FOUNDATION_EXPORT double PanModalVersionNumber;
//! Project version string for PanModal.
FOUNDATION_EXPORT const unsigned char PanModalVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <PanModal/PublicHeader.h>
+5 -1
View File
@@ -1,6 +1,6 @@
//
// PanModalHeight.swift
// SlackUI
// PanModal
//
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
@@ -35,4 +35,8 @@ public enum PanModalHeight: Equatable {
*/
case contentHeightIgnoringSafeArea(CGFloat)
/**
Sets the height to be the intrinsic content height
*/
case intrinsicHeight
}
@@ -2,7 +2,6 @@
// PanModalPresentable+Defaults.swift
// PanModal
//
// Created by Stephen Sowole on 11/5/18.
// Copyright © 2018 Tiny Speck, Inc. All rights reserved.
//
@@ -31,16 +30,28 @@ public extension PanModalPresentable where Self: UIViewController {
return .contentHeight(scrollView.contentSize.height)
}
var cornerRadius: CGFloat {
return 8.0
}
var springDamping: CGFloat {
return 0.8
}
var transitionDuration: Double {
return PanModalAnimator.Constants.defaultTransitionDuration
}
var transitionAnimationOptions: UIView.AnimationOptions {
return [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState]
}
var backgroundAlpha: CGFloat {
return 0.7
}
var scrollIndicatorInsets: UIEdgeInsets {
let top = shouldRoundTopCorners ? PanModalPresentationController.Constants.cornerRadius : 0
let top = shouldRoundTopCorners ? cornerRadius : 0
return UIEdgeInsets(top: CGFloat(top), left: 0, bottom: bottomLayoutOffset, right: 0)
}
@@ -61,10 +72,6 @@ public extension PanModalPresentable where Self: UIViewController {
return true
}
var isPanScrollEnabled: Bool {
return true
}
var isUserInteractionEnabled: Bool {
return true
}
@@ -81,7 +88,11 @@ public extension PanModalPresentable where Self: UIViewController {
return shouldRoundTopCorners
}
func willRespond(to panGestureRecognizer: UIPanGestureRecognizer) {
func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool {
return true
}
func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) {
}
@@ -38,7 +38,7 @@ extension PanModalPresentable where Self: UIViewController {
}
/**
Returns the short form Y postion
Returns the short form Y position
- Note: If voiceover is on, the `longFormYPos` is returned.
We do not support short form when voiceover is on as it would make it difficult for user to navigate.
@@ -55,7 +55,7 @@ extension PanModalPresentable where Self: UIViewController {
}
/**
Returns the long form Y postion
Returns the long form Y position
- Note: We cap this value to the max possible height
to ensure content is not rendered outside of the view bounds
@@ -90,6 +90,12 @@ extension PanModalPresentable where Self: UIViewController {
return bottomYPos - (height + bottomLayoutOffset)
case .contentHeightIgnoringSafeArea(let height):
return bottomYPos - height
case .intrinsicHeight:
view.layoutIfNeeded()
let targetSize = CGSize(width: (presentedVC?.containerView?.bounds ?? UIScreen.main.bounds).width,
height: UIView.layoutFittingCompressedSize.height)
let intrinsicHeight = view.systemLayoutSizeFitting(targetSize).height
return bottomYPos - (intrinsicHeight + bottomLayoutOffset)
}
}
+39 -17
View File
@@ -13,12 +13,12 @@ import UIKit
Usage:
```
extension UIViewController: PanModalPresentable {
extension YourViewController: PanModalPresentable {
func shouldRoundTopCorners: Bool { return false }
}
```
*/
public protocol PanModalPresentable {
public protocol PanModalPresentable: AnyObject {
/**
The scroll view embedded in the view controller.
@@ -54,6 +54,13 @@ public protocol PanModalPresentable {
*/
var longFormHeight: PanModalHeight { get }
/**
The corner radius used when `shouldRoundTopCorners` is enabled.
Default Value is 8.0.
*/
var cornerRadius: CGFloat { get }
/**
The springDamping value used to determine the amount of 'bounce'
seen when transitioning to short/long form.
@@ -62,6 +69,22 @@ public protocol PanModalPresentable {
*/
var springDamping: CGFloat { get }
/**
The transitionDuration value is used to set the speed of animation during a transition,
including initial presentation.
Default value is 0.5.
*/
var transitionDuration: Double { get }
/**
The animation options used when performing animations on the PanModal, utilized mostly
during a transition.
Default value is [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState].
*/
var transitionAnimationOptions: UIView.AnimationOptions { get }
/**
The background view alpha.
@@ -91,29 +114,19 @@ public protocol PanModalPresentable {
A flag to determine if scrolling should seamlessly transition from the pan modal container view to
the embedded scroll view once the scroll limit has been reached.
Default value is false.
Unless a scrollView is provided and the content exceeds the longForm height
Default value is false. Unless a scrollView is provided and the content height exceeds the longForm height.
*/
var allowsExtendedPanScrolling: Bool { get }
/**
A flag to determine if dismissal should be initiated when swiping down on the presented view.
Return false to fallback to the short form state instead of dismissing.
Default value is true.
*/
var allowsDragToDismiss: Bool { get }
/**
A flag to determine if scrolling should be enabled on the entire view.
- Note: Returning false will disable scrolling on the embedded scrollview as well as on the
pan modal container view.
Default value is true.
*/
var isPanScrollEnabled: Bool { get }
/**
A flag to toggle user interactions on the container view.
@@ -145,6 +158,15 @@ public protocol PanModalPresentable {
*/
var showDragIndicator: Bool { get }
/**
Asks the delegate if the pan modal should respond to the pan modal gesture recognizer.
Return false to disable movement on the pan modal but maintain gestures on the presented view.
Default value is true.
*/
func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool
/**
Notifies the delegate when the pan modal gesture recognizer state is either
`began` or `changed`. This method gives the delegate a chance to prepare
@@ -154,7 +176,7 @@ public protocol PanModalPresentable {
Default value is an empty implementation.
*/
func willRespond(to panGestureRecognizer: UIPanGestureRecognizer)
func willRespond(to panModalGestureRecognizer: UIPanGestureRecognizer)
/**
Asks the delegate if the pan modal gesture recognizer should be prioritized.
@@ -162,8 +184,8 @@ public protocol PanModalPresentable {
For example, you can use this to define a region
where you would like to restrict where the pan gesture can start.
If false, then we rely on the internal conditions of when a pan gesture
should succeed or fail, such as, if we're actively scrolling on the scrollView
If false, then we rely solely on the internal conditions of when a pan gesture
should succeed or fail, such as, if we're actively scrolling on the scrollView.
Default return value is false.
*/
+2 -2
View File
@@ -1,6 +1,6 @@
//
// PanModalPresenter.swift
// SlackUI
// PanModal
//
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
@@ -17,7 +17,7 @@ import UIKit
sourceRect: .zero)
```
*/
public protocol PanModalPresenter {
protocol PanModalPresenter: AnyObject {
/**
A flag that returns true if the current presented view controller
@@ -1,6 +1,6 @@
//
// UIViewController+PanModalPresenterProtocol.swift
// SlackUI
// PanModal
//
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
//
@@ -50,6 +50,7 @@ extension UIViewController: PanModalPresenter {
viewControllerToPresent.popoverPresentationController?.delegate = PanModalPresentationDelegate.default
} else {
viewControllerToPresent.modalPresentationStyle = .custom
viewControllerToPresent.modalPresentationCapturesStatusBarAppearance = true
viewControllerToPresent.transitioningDelegate = PanModalPresentationDelegate.default
}
+5 -2
View File
@@ -20,8 +20,9 @@ class PanContainerView: UIView {
addSubview(presentedView)
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError()
fatalError("init(coder:) has not been implemented")
}
}
@@ -33,7 +34,9 @@ extension UIView {
from the view hierachy
*/
var panContainerView: PanContainerView? {
return subviews.compactMap({ $0 as? PanContainerView }).first
return subviews.first(where: { view -> Bool in
view is PanContainerView
}) as? PanContainerView
}
}
@@ -7,6 +7,22 @@
objects = {
/* Begin PBXBuildFile section */
0F2A2C552239C119003BDB2F /* PanModal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2A2C532239C119003BDB2F /* PanModal.h */; settings = {ATTRIBUTES = (Public, ); }; };
0F2A2C582239C119003BDB2F /* PanModal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F2A2C512239C119003BDB2F /* PanModal.framework */; };
0F2A2C592239C119003BDB2F /* PanModal.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0F2A2C512239C119003BDB2F /* PanModal.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
0F2A2C5E2239C137003BDB2F /* PanModalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A2220BA6E500124CE1 /* PanModalAnimator.swift */; };
0F2A2C5F2239C139003BDB2F /* PanModalPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC139066216D9458007A3E64 /* PanModalPresentationAnimator.swift */; };
0F2A2C602239C13C003BDB2F /* PanModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906C216D9458007A3E64 /* PanModalPresentationController.swift */; };
0F2A2C612239C140003BDB2F /* PanModalPresentationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94795C9A21F0335D008045A0 /* PanModalPresentationDelegate.swift */; };
0F2A2C622239C148003BDB2F /* PanModalHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A4220BA76D00124CE1 /* PanModalHeight.swift */; };
0F2A2C632239C14B003BDB2F /* PanModalPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC139068216D9458007A3E64 /* PanModalPresentable.swift */; };
0F2A2C642239C14E003BDB2F /* PanModalPresentable+Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC0EE7B21917F2500208DBC /* PanModalPresentable+Defaults.swift */; };
0F2A2C652239C151003BDB2F /* PanModalPresentable+UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC139069216D9458007A3E64 /* PanModalPresentable+UIViewController.swift */; };
0F2A2C662239C153003BDB2F /* PanModalPresentable+LayoutHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A6220BA78800124CE1 /* PanModalPresentable+LayoutHelpers.swift */; };
0F2A2C672239C157003BDB2F /* PanModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906A216D9458007A3E64 /* PanModalPresenter.swift */; };
0F2A2C682239C15D003BDB2F /* UIViewController+PanModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A9220BA82A00124CE1 /* UIViewController+PanModalPresenter.swift */; };
0F2A2C692239C162003BDB2F /* DimmedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13906E216D9458007A3E64 /* DimmedView.swift */; };
0F2A2C6A2239C165003BDB2F /* PanContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94795C9C21F03368008045A0 /* PanContainerView.swift */; };
743CABB02225FC9F00634A5A /* UserGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABAF2225FC9F00634A5A /* UserGroupViewController.swift */; };
743CABB22225FD1100634A5A /* UserGroupHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABB12225FD1100634A5A /* UserGroupHeaderView.swift */; };
743CABB42225FE7700634A5A /* UserGroupMemberPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABB32225FE7700634A5A /* UserGroupMemberPresentable.swift */; };
@@ -25,6 +41,7 @@
943904ED2226366700859537 /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943904EC2226366700859537 /* AlertViewController.swift */; };
943904EF2226383700859537 /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943904EE2226383700859537 /* NavigationController.swift */; };
943904F32226484F00859537 /* UserGroupStackedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943904F22226484F00859537 /* UserGroupStackedViewController.swift */; };
944EBA2E227BB7F400C4C97B /* FullScreenNavController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944EBA2D227BB7F400C4C97B /* FullScreenNavController.swift */; };
94795C9B21F0335D008045A0 /* PanModalPresentationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94795C9A21F0335D008045A0 /* PanModalPresentationDelegate.swift */; };
94795C9D21F03368008045A0 /* PanContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94795C9C21F03368008045A0 /* PanContainerView.swift */; };
DC13905E216D90D5007A3E64 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC13905D216D90D5007A3E64 /* Assets.xcassets */; };
@@ -42,6 +59,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
0F2A2C562239C119003BDB2F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DCA741A2216D90410021F2F2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0F2A2C502239C119003BDB2F;
remoteInfo = PanModal;
};
743CABC92226171500634A5A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DCA741A2216D90410021F2F2 /* Project object */;
@@ -51,7 +75,24 @@
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0F2A2C5D2239C119003BDB2F /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
0F2A2C592239C119003BDB2F /* PanModal.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0F2A2C512239C119003BDB2F /* PanModal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PanModal.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0F2A2C532239C119003BDB2F /* PanModal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PanModal.h; sourceTree = "<group>"; };
0F2A2C542239C119003BDB2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
743CABAF2225FC9F00634A5A /* UserGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupViewController.swift; sourceTree = "<group>"; };
743CABB12225FD1100634A5A /* UserGroupHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupHeaderView.swift; sourceTree = "<group>"; };
743CABB32225FE7700634A5A /* UserGroupMemberPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupMemberPresentable.swift; sourceTree = "<group>"; };
@@ -72,6 +113,7 @@
943904EC2226366700859537 /* AlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = "<group>"; };
943904EE2226383700859537 /* NavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = "<group>"; };
943904F22226484F00859537 /* UserGroupStackedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupStackedViewController.swift; sourceTree = "<group>"; };
944EBA2D227BB7F400C4C97B /* FullScreenNavController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenNavController.swift; sourceTree = "<group>"; };
94795C9A21F0335D008045A0 /* PanModalPresentationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalPresentationDelegate.swift; sourceTree = "<group>"; };
94795C9C21F03368008045A0 /* PanContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanContainerView.swift; sourceTree = "<group>"; };
DC13905D216D90D5007A3E64 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -84,13 +126,20 @@
DC13906E216D9458007A3E64 /* DimmedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DimmedView.swift; sourceTree = "<group>"; };
DC3B2EB9222A560A000C8A4A /* TransientAlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransientAlertViewController.swift; sourceTree = "<group>"; };
DC3B2EBD222A58C9000C8A4A /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = "<group>"; };
DCA741AA216D90410021F2F2 /* PanModal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanModal.app; sourceTree = BUILT_PRODUCTS_DIR; };
DCA741AA216D90410021F2F2 /* PanModalDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PanModalDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
DCA741AD216D90410021F2F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
DCA741B9216D90420021F2F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DCC0EE7B21917F2500208DBC /* PanModalPresentable+Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PanModalPresentable+Defaults.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0F2A2C4E2239C119003BDB2F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
743CABC12226171500634A5A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -102,12 +151,22 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0F2A2C582239C119003BDB2F /* PanModal.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0F2A2C522239C119003BDB2F /* PanModal */ = {
isa = PBXGroup;
children = (
0F2A2C532239C119003BDB2F /* PanModal.h */,
0F2A2C542239C119003BDB2F /* Info.plist */,
);
path = PanModal;
sourceTree = "<group>";
};
743CABAE2225FC4A00634A5A /* User Groups */ = {
isa = PBXGroup;
children = (
@@ -181,6 +240,22 @@
path = Presenter;
sourceTree = "<group>";
};
944EBA2B227BB7D900C4C97B /* Basic */ = {
isa = PBXGroup;
children = (
943904EA2226354100859537 /* BasicViewController.swift */,
);
path = Basic;
sourceTree = "<group>";
};
944EBA2C227BB7E100C4C97B /* Full Screen */ = {
isa = PBXGroup;
children = (
944EBA2D227BB7F400C4C97B /* FullScreenNavController.swift */,
);
path = "Full Screen";
sourceTree = "<group>";
};
DC13905F216D93AB007A3E64 /* Resources */ = {
isa = PBXGroup;
children = (
@@ -253,7 +328,8 @@
DC139079216D9AAA007A3E64 /* View Controllers */ = {
isa = PBXGroup;
children = (
943904EA2226354100859537 /* BasicViewController.swift */,
944EBA2B227BB7D900C4C97B /* Basic */,
944EBA2C227BB7E100C4C97B /* Full Screen */,
DC3B2EBB222A5882000C8A4A /* Alert */,
DC3B2EBC222A5893000C8A4A /* Alert (Transient) */,
743CB2AB222661EA00665A55 /* User Groups (Stacked) */,
@@ -286,6 +362,7 @@
DCA741AC216D90410021F2F2 /* Sample */,
DC139062216D9431007A3E64 /* PanModal */,
743CABC52226171500634A5A /* Tests */,
0F2A2C522239C119003BDB2F /* PanModal */,
DCA741AB216D90410021F2F2 /* Products */,
);
sourceTree = "<group>";
@@ -293,8 +370,9 @@
DCA741AB216D90410021F2F2 /* Products */ = {
isa = PBXGroup;
children = (
DCA741AA216D90410021F2F2 /* PanModal.app */,
DCA741AA216D90410021F2F2 /* PanModalDemo.app */,
743CABC42226171500634A5A /* PanModalTests.xctest */,
0F2A2C512239C119003BDB2F /* PanModal.framework */,
);
name = Products;
sourceTree = "<group>";
@@ -312,7 +390,36 @@
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
0F2A2C4C2239C119003BDB2F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
0F2A2C552239C119003BDB2F /* PanModal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
0F2A2C502239C119003BDB2F /* PanModal */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0F2A2C5A2239C119003BDB2F /* Build configuration list for PBXNativeTarget "PanModal" */;
buildPhases = (
0F2A2C4C2239C119003BDB2F /* Headers */,
0F2A2C4D2239C119003BDB2F /* Sources */,
0F2A2C4E2239C119003BDB2F /* Frameworks */,
0F2A2C4F2239C119003BDB2F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = PanModal;
productName = PanModal;
productReference = 0F2A2C512239C119003BDB2F /* PanModal.framework */;
productType = "com.apple.product-type.framework";
};
743CABC32226171500634A5A /* PanModalTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 743CABCB2226171500634A5A /* Build configuration list for PBXNativeTarget "PanModalTests" */;
@@ -331,21 +438,23 @@
productReference = 743CABC42226171500634A5A /* PanModalTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
DCA741A9216D90410021F2F2 /* PanModal */ = {
DCA741A9216D90410021F2F2 /* PanModalDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = DCA741BC216D90420021F2F2 /* Build configuration list for PBXNativeTarget "PanModal" */;
buildConfigurationList = DCA741BC216D90420021F2F2 /* Build configuration list for PBXNativeTarget "PanModalDemo" */;
buildPhases = (
DCA741A6216D90410021F2F2 /* Sources */,
DCA741A7216D90410021F2F2 /* Frameworks */,
DCA741A8216D90410021F2F2 /* Resources */,
0F2A2C5D2239C119003BDB2F /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
0F2A2C572239C119003BDB2F /* PBXTargetDependency */,
);
name = PanModal;
name = PanModalDemo;
productName = PanModal;
productReference = DCA741AA216D90410021F2F2 /* PanModal.app */;
productReference = DCA741AA216D90410021F2F2 /* PanModalDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@@ -358,6 +467,9 @@
LastUpgradeCheck = 1000;
ORGANIZATIONNAME = Detail;
TargetAttributes = {
0F2A2C502239C119003BDB2F = {
CreatedOnToolsVersion = 10.1;
};
743CABC32226171500634A5A = {
CreatedOnToolsVersion = 10.1;
TestTargetID = DCA741A9216D90410021F2F2;
@@ -367,7 +479,7 @@
};
};
};
buildConfigurationList = DCA741A5216D90410021F2F2 /* Build configuration list for PBXProject "PanModal" */;
buildConfigurationList = DCA741A5216D90410021F2F2 /* Build configuration list for PBXProject "PanModalDemo" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
@@ -380,13 +492,21 @@
projectDirPath = "";
projectRoot = "";
targets = (
DCA741A9216D90410021F2F2 /* PanModal */,
DCA741A9216D90410021F2F2 /* PanModalDemo */,
743CABC32226171500634A5A /* PanModalTests */,
0F2A2C502239C119003BDB2F /* PanModal */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0F2A2C4F2239C119003BDB2F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
743CABC22226171500634A5A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -407,6 +527,26 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0F2A2C4D2239C119003BDB2F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0F2A2C5E2239C137003BDB2F /* PanModalAnimator.swift in Sources */,
0F2A2C5F2239C139003BDB2F /* PanModalPresentationAnimator.swift in Sources */,
0F2A2C602239C13C003BDB2F /* PanModalPresentationController.swift in Sources */,
0F2A2C612239C140003BDB2F /* PanModalPresentationDelegate.swift in Sources */,
0F2A2C622239C148003BDB2F /* PanModalHeight.swift in Sources */,
0F2A2C632239C14B003BDB2F /* PanModalPresentable.swift in Sources */,
0F2A2C642239C14E003BDB2F /* PanModalPresentable+Defaults.swift in Sources */,
0F2A2C652239C151003BDB2F /* PanModalPresentable+UIViewController.swift in Sources */,
0F2A2C662239C153003BDB2F /* PanModalPresentable+LayoutHelpers.swift in Sources */,
0F2A2C672239C157003BDB2F /* PanModalPresenter.swift in Sources */,
0F2A2C682239C15D003BDB2F /* UIViewController+PanModalPresenter.swift in Sources */,
0F2A2C692239C162003BDB2F /* DimmedView.swift in Sources */,
0F2A2C6A2239C165003BDB2F /* PanContainerView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
743CABC02226171500634A5A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -446,6 +586,7 @@
DC139075216D9458007A3E64 /* DimmedView.swift in Sources */,
743CABD322265F2E00634A5A /* ProfileViewController.swift in Sources */,
DC139070216D9458007A3E64 /* PanModalPresentationAnimator.swift in Sources */,
944EBA2E227BB7F400C4C97B /* FullScreenNavController.swift in Sources */,
DCA741AE216D90410021F2F2 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -453,14 +594,77 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
0F2A2C572239C119003BDB2F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0F2A2C502239C119003BDB2F /* PanModal */;
targetProxy = 0F2A2C562239C119003BDB2F /* PBXContainerItemProxy */;
};
743CABCA2226171500634A5A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DCA741A9216D90410021F2F2 /* PanModal */;
target = DCA741A9216D90410021F2F2 /* PanModalDemo */;
targetProxy = 743CABC92226171500634A5A /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
0F2A2C5B2239C119003BDB2F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 6UF7FN999R;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = PanModal/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.slack.PanModal;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
0F2A2C5C2239C119003BDB2F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 6UF7FN999R;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = PanModal/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.slack.PanModal;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
743CABCC2226171500634A5A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -477,7 +681,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModal.app/PanModal";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModalDemo.app/PanModalDemo";
};
name = Debug;
};
@@ -497,7 +701,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModal.app/PanModal";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PanModalDemo.app/PanModalDemo";
};
name = Release;
};
@@ -620,6 +824,7 @@
DCA741BD216D90420021F2F2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_STYLE = Automatic;
@@ -640,6 +845,7 @@
DCA741BE216D90420021F2F2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_STYLE = Automatic;
@@ -660,6 +866,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0F2A2C5A2239C119003BDB2F /* Build configuration list for PBXNativeTarget "PanModal" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0F2A2C5B2239C119003BDB2F /* Debug */,
0F2A2C5C2239C119003BDB2F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
743CABCB2226171500634A5A /* Build configuration list for PBXNativeTarget "PanModalTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -669,7 +884,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DCA741A5216D90410021F2F2 /* Build configuration list for PBXProject "PanModal" */ = {
DCA741A5216D90410021F2F2 /* Build configuration list for PBXProject "PanModalDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DCA741BA216D90420021F2F2 /* Debug */,
@@ -678,7 +893,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DCA741BC216D90420021F2F2 /* Build configuration list for PBXNativeTarget "PanModal" */ = {
DCA741BC216D90420021F2F2 /* Build configuration list for PBXNativeTarget "PanModalDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DCA741BD216D90420021F2F2 /* Debug */,
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0F2A2C502239C119003BDB2F"
BuildableName = "PanModal.framework"
BlueprintName = "PanModal"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0F2A2C502239C119003BDB2F"
BuildableName = "PanModal.framework"
BlueprintName = "PanModal"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0F2A2C502239C119003BDB2F"
BuildableName = "PanModal.framework"
BlueprintName = "PanModal"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DCA741A9216D90410021F2F2"
BuildableName = "PanModalDemo.app"
BlueprintName = "PanModalDemo"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "743CABC32226171500634A5A"
BuildableName = "PanModalTests.xctest"
BlueprintName = "PanModalTests"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DCA741A9216D90410021F2F2"
BuildableName = "PanModalDemo.app"
BlueprintName = "PanModalDemo"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DCA741A9216D90410021F2F2"
BuildableName = "PanModalDemo.app"
BlueprintName = "PanModalDemo"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DCA741A9216D90410021F2F2"
BuildableName = "PanModalDemo.app"
BlueprintName = "PanModalDemo"
ReferencedContainer = "container:PanModalDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+19 -12
View File
@@ -67,6 +67,7 @@ private extension SampleViewController {
enum RowType: Int, CaseIterable {
case basic
case fullScreen
case alert
case transientAlert
case userGroups
@@ -77,6 +78,7 @@ private extension SampleViewController {
var presentable: RowPresentable {
switch self {
case .basic: return Basic()
case .fullScreen: return FullScreen()
case .alert: return Alert()
case .transientAlert: return TransientAlert()
case .userGroups: return UserGroup()
@@ -86,33 +88,38 @@ private extension SampleViewController {
}
struct Basic: RowPresentable {
var string: String { return "Basic" }
var rowVC: PanModalPresentable.LayoutType { return BasicViewController() }
let string: String = "Basic"
let rowVC: PanModalPresentable.LayoutType = BasicViewController()
}
struct FullScreen: RowPresentable {
let string: String = "Full Screen"
let rowVC: PanModalPresentable.LayoutType = FullScreenNavController()
}
struct Alert: RowPresentable {
var string: String { return "Alert" }
var rowVC: PanModalPresentable.LayoutType { return AlertViewController() }
let string: String = "Alert"
let rowVC: PanModalPresentable.LayoutType = AlertViewController()
}
struct TransientAlert: RowPresentable {
var string: String { return "Alert (Transient)"}
var rowVC: PanModalPresentable.LayoutType { return TransientAlertViewController() }
let string: String = "Alert (Transient)"
let rowVC: PanModalPresentable.LayoutType = TransientAlertViewController()
}
struct UserGroup: RowPresentable {
var string: String { return "User Groups" }
var rowVC: PanModalPresentable.LayoutType { return UserGroupViewController() }
let string: String = "User Groups"
let rowVC: PanModalPresentable.LayoutType = UserGroupViewController()
}
struct Navigation: RowPresentable {
var string: String { return "User Groups (NavigationController)" }
var rowVC: PanModalPresentable.LayoutType { return NavigationController() }
let string: String = "User Groups (NavigationController)"
let rowVC: PanModalPresentable.LayoutType = NavigationController()
}
struct Stacked: RowPresentable {
var string: String { return "User Groups (Stacked)" }
var rowVC: PanModalPresentable.LayoutType { return UserGroupStackedViewController() }
let string: String = "User Groups (Stacked)"
let rowVC: PanModalPresentable.LayoutType = UserGroupStackedViewController()
}
}
}
@@ -18,6 +18,10 @@ class BasicViewController: UIViewController {
extension BasicViewController: PanModalPresentable {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
var panScrollable: UIScrollView? {
return nil
}
@@ -0,0 +1,73 @@
//
// FullScreenNavController.swift
// PanModalDemo
//
// Created by Stephen Sowole on 5/2/19.
// Copyright © 2019 Detail. All rights reserved.
//
import UIKit
class FullScreenNavController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
pushViewController(FullScreenViewController(), animated: false)
}
}
extension FullScreenNavController: PanModalPresentable {
var panScrollable: UIScrollView? {
return nil
}
var topOffset: CGFloat {
return 0.0
}
var springDamping: CGFloat {
return 1.0
}
var transitionDuration: Double {
return 0.4
}
var transitionAnimationOptions: UIView.AnimationOptions {
return [.allowUserInteraction, .beginFromCurrentState]
}
var shouldRoundTopCorners: Bool {
return false
}
var showDragIndicator: Bool {
return false
}
}
private class FullScreenViewController: UIViewController {
let textLabel: UILabel = {
let label = UILabel()
label.text = "Drag downwards to dismiss"
label.font = UIFont(name: "Lato-Bold", size: 17)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
title = "Full Screen"
view.backgroundColor = .white
setupConstraints()
}
private func setupConstraints() {
view.addSubview(textLabel)
textLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
@@ -12,6 +12,10 @@ class NavigationController: UINavigationController, PanModalPresentable {
private let navGroups = NavUserGroups()
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
pushViewController(navGroups, animated: false)
@@ -14,6 +14,10 @@ class StackedProfileViewController: UIViewController, PanModalPresentable {
let presentable: UserGroupMemberPresentable
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
// MARK: - Views
let avatarView: UIView = {
@@ -85,6 +89,7 @@ class StackedProfileViewController: UIViewController, PanModalPresentable {
roleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
roleLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 4.0).isActive = true
bottomLayoutGuide.topAnchor.constraint(greaterThanOrEqualTo: roleLabel.bottomAnchor).isActive = true
}
// MARK: - Pan Modal Presentable
@@ -94,7 +99,7 @@ class StackedProfileViewController: UIViewController, PanModalPresentable {
}
var longFormHeight: PanModalHeight {
return .contentHeight(300)
return .intrinsicHeight
}
var anchorModalToLongForm: Bool {
@@ -8,7 +8,7 @@
import UIKit
class UserGroupViewController: UITableViewController, PanModalPresentable, UIGestureRecognizerDelegate {
class UserGroupViewController: UITableViewController, PanModalPresentable {
let members: [UserGroupMemberPresentable] = [
UserGroupMemberPresentable(name: "Naida Schill ✈️", role: "Staff Engineer - Mobile DevXP", avatarBackgroundColor: #colorLiteral(red: 0.7215686275, green: 0.9098039216, blue: 0.5607843137, alpha: 1)),
@@ -34,6 +34,10 @@ class UserGroupViewController: UITableViewController, PanModalPresentable, UIGes
var isShortFormEnabled = true
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
let headerView = UserGroupHeaderView()
let headerPresentable = UserGroupHeaderPresentable.init(handle: "ios-engs", description: "iOS Engineers", memberCount: 10)
+3 -1
View File
@@ -53,12 +53,14 @@ class PanModalTests: XCTestCase {
XCTAssertEqual(vc.anchorModalToLongForm, true)
XCTAssertEqual(vc.allowsExtendedPanScrolling, false)
XCTAssertEqual(vc.allowsDragToDismiss, true)
XCTAssertEqual(vc.isPanScrollEnabled, true)
XCTAssertEqual(vc.isUserInteractionEnabled, true)
XCTAssertEqual(vc.isHapticFeedbackEnabled, true)
XCTAssertEqual(vc.shouldRoundTopCorners, false)
XCTAssertEqual(vc.showDragIndicator, false)
XCTAssertEqual(vc.shouldRoundTopCorners, false)
XCTAssertEqual(vc.cornerRadius, 8.0)
XCTAssertEqual(vc.transitionDuration, PanModalAnimator.Constants.defaultTransitionDuration)
XCTAssertEqual(vc.transitionAnimationOptions, [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState])
}
func testPresentableYValues() {