23 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
16 changed files with 246 additions and 54 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'PanModal'
s.version = '1.2'
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.
+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 {
@@ -198,7 +198,7 @@ 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
@@ -213,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
@@ -220,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 }
@@ -244,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 }
@@ -273,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)
@@ -342,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)
}
/**
@@ -384,7 +408,7 @@ private extension PanModalPresentationController {
}
/**
Caluclates & stores the layout anchor points & options
Calculates & stores the layout anchor points & options
*/
func configureViewLayout() {
@@ -443,7 +467,7 @@ private extension PanModalPresentationController {
@objc func didPanOnPresentedView(_ recognizer: UIPanGestureRecognizer) {
guard
shouldRespond(to: panGestureRecognizer),
shouldRespond(to: recognizer),
let containerView = containerView
else {
recognizer.setTranslation(.zero, in: recognizer.view)
@@ -484,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)
@@ -498,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)
@@ -635,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
}
/**
@@ -802,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
}
}
@@ -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
}
@@ -38,6 +38,14 @@ public extension PanModalPresentable where Self: UIViewController {
return 0.8
}
var transitionDuration: Double {
return PanModalAnimator.Constants.defaultTransitionDuration
}
var transitionAnimationOptions: UIView.AnimationOptions {
return [.curveEaseInOut, .allowUserInteraction, .beginFromCurrentState]
}
var backgroundAlpha: CGFloat {
return 0.7
}
@@ -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
+17 -1
View File
@@ -18,7 +18,7 @@ import UIKit
}
```
*/
public protocol PanModalPresentable {
public protocol PanModalPresentable: AnyObject {
/**
The scroll view embedded in the view controller.
@@ -69,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.
+1 -1
View File
@@ -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
+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
}
}
+21 -1
View File
@@ -41,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 */; };
@@ -112,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>"; };
@@ -238,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 = (
@@ -310,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) */,
@@ -567,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;
+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()
}
}
}
@@ -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
}
}
@@ -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)),
+2
View File
@@ -59,6 +59,8 @@ class PanModalTests: XCTestCase {
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() {