Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9fedcb597 | |||
| 4206308afd | |||
| 0234d82979 | |||
| b0fb9e7eed | |||
| a9edeb1d71 | |||
| b8f7e613ec | |||
| 8a662e829b | |||
| 0b2152f878 | |||
| 13251e1db7 | |||
| da4c94e47e | |||
| 0d999396a5 | |||
| 8e39823698 | |||
| 457ebaed94 | |||
| 32e4a6fa24 | |||
| 2736468072 | |||
| c76ae09bc9 | |||
| 12d6380d07 | |||
| 77c9f6f806 | |||
| 964d444ff6 | |||
| 9456969502 | |||
| 0750bd980e |
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'PanModal'
|
||||
s.version = '1.2.2'
|
||||
s.version = '1.2.4'
|
||||
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.
|
||||
|
||||
@@ -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,7 +150,13 @@ 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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
@@ -223,7 +243,7 @@ public extension 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 }
|
||||
@@ -247,7 +267,7 @@ public extension PanModalPresentationController {
|
||||
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 }
|
||||
@@ -278,7 +298,7 @@ public extension PanModalPresentationController {
|
||||
- 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)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -798,11 +822,11 @@ extension PanModalPresentationController: UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
/**
|
||||
Allow simultaneous gesture recognizers only when the other gesture recognizer
|
||||
is a pan gesture recognizer
|
||||
Allow simultaneous gesture recognizers only when the other gesture recognizer's view
|
||||
is the pan scrollable view
|
||||
*/
|
||||
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self)
|
||||
return otherGestureRecognizer.view == presentable?.panScrollable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user