Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dab02d34c0 | |||
| 96591ef52c | |||
| 1defbf2a47 | |||
| b58552279e | |||
| ef7f00dab7 | |||
| d70dce231f | |||
| 5baac6732e | |||
| 1d8b218056 | |||
| ae78bd6f64 | |||
| 2b3029333e | |||
| f71fa70302 | |||
| 6438b952cc | |||
| a7d7033ef0 | |||
| 3f3124ae37 | |||
| 0da0a44c4a | |||
| 88dc3324f6 | |||
| d0b094292f | |||
| 15f39a1929 | |||
| 21bcb6f268 | |||
| f7cb63caaa |
+1
-1
@@ -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.
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'PanModal'
|
||||
s.version = '1.0.2'
|
||||
s.version = '1.2'
|
||||
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.
|
||||
@@ -25,5 +25,5 @@ Pod::Spec.new do |s|
|
||||
s.social_media_url = 'https://twitter.com/slackhq'
|
||||
s.ios.deployment_target = '10.0'
|
||||
s.swift_version = '4.2'
|
||||
s.source_files = 'PanModal/**/*'
|
||||
s.source_files = 'PanModal/**/*.{swift,h,m}'
|
||||
end
|
||||
|
||||
@@ -124,7 +124,7 @@ extension PanModalPresentationAnimator: UIViewControllerAnimatedTransitioning {
|
||||
}
|
||||
|
||||
/**
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -219,7 +220,7 @@ public class PanModalPresentationController: UIPresentationController {
|
||||
public extension PanModalPresentationController {
|
||||
|
||||
/**
|
||||
Tranisition the PanModalPresentationController
|
||||
Transition the PanModalPresentationController
|
||||
to the given presentation state
|
||||
*/
|
||||
public func transition(to state: PresentationState) {
|
||||
@@ -243,7 +244,7 @@ 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) {
|
||||
@@ -272,7 +273,7 @@ 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
|
||||
@@ -383,7 +384,7 @@ private extension PanModalPresentationController {
|
||||
}
|
||||
|
||||
/**
|
||||
Caluclates & stores the layout anchor points & options
|
||||
Calculates & stores the layout anchor points & options
|
||||
*/
|
||||
func configureViewLayout() {
|
||||
|
||||
@@ -413,7 +414,6 @@ private extension PanModalPresentationController {
|
||||
to avoid visual bugs
|
||||
*/
|
||||
scrollView.showsVerticalScrollIndicator = false
|
||||
scrollView.isScrollEnabled = presentable?.isPanScrollEnabled ?? true
|
||||
scrollView.scrollIndicatorInsets = presentable?.scrollIndicatorInsets ?? .zero
|
||||
|
||||
/**
|
||||
@@ -443,8 +443,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 +484,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 +498,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 +513,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 +568,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 +595,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 +635,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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -797,37 +816,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
|
||||
}
|
||||
|
||||
@@ -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,6 +30,10 @@ public extension PanModalPresentable where Self: UIViewController {
|
||||
return .contentHeight(scrollView.contentSize.height)
|
||||
}
|
||||
|
||||
var cornerRadius: CGFloat {
|
||||
return 8.0
|
||||
}
|
||||
|
||||
var springDamping: CGFloat {
|
||||
return 0.8
|
||||
}
|
||||
@@ -40,7 +43,7 @@ public extension PanModalPresentable where Self: UIViewController {
|
||||
}
|
||||
|
||||
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 +64,6 @@ public extension PanModalPresentable where Self: UIViewController {
|
||||
return true
|
||||
}
|
||||
|
||||
var isPanScrollEnabled: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var isUserInteractionEnabled: Bool {
|
||||
return true
|
||||
}
|
||||
@@ -81,7 +80,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import UIKit
|
||||
|
||||
Usage:
|
||||
```
|
||||
extension UIViewController: PanModalPresentable {
|
||||
extension YourViewController: PanModalPresentable {
|
||||
func shouldRoundTopCorners: Bool { return false }
|
||||
}
|
||||
```
|
||||
@@ -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.
|
||||
@@ -91,29 +98,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 +142,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 +160,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 +168,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.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// PanModalPresenter.swift
|
||||
// SlackUI
|
||||
// PanModal
|
||||
//
|
||||
// Copyright © 2019 Tiny Speck, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -661,7 +661,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;
|
||||
};
|
||||
@@ -681,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 = Release;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
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
|
||||
|
||||
@@ -18,6 +18,10 @@ class BasicViewController: UIViewController {
|
||||
|
||||
extension BasicViewController: PanModalPresentable {
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return .lightContent
|
||||
}
|
||||
|
||||
var panScrollable: UIScrollView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -53,12 +53,12 @@ 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)
|
||||
}
|
||||
|
||||
func testPresentableYValues() {
|
||||
|
||||
Reference in New Issue
Block a user