From 89bb53294eacbf4bb1cff87d3ee2f2fc119a61b4 Mon Sep 17 00:00:00 2001 From: Kyle Bashour Date: Sun, 21 Feb 2021 12:27:14 -0800 Subject: [PATCH 1/2] Update animations to use UIViewPropertyAnimator --- PanModal/Animator/PanModalAnimator.swift | 33 ++++++++++--------- .../PanModalPresentationAnimator.swift | 4 +-- .../PanModalPresentable+Defaults.swift | 16 +++------ .../Presentable/PanModalPresentable.swift | 31 ++++------------- PanModalDemo.xcodeproj/project.pbxproj | 12 +++---- .../Alert/AlertViewController.swift | 6 ++++ .../Full Screen/FullScreenNavController.swift | 12 ------- Tests/PanModalTests.swift | 3 -- 8 files changed, 42 insertions(+), 75 deletions(-) diff --git a/PanModal/Animator/PanModalAnimator.swift b/PanModal/Animator/PanModalAnimator.swift index 712dd5d2..4e04644f 100644 --- a/PanModal/Animator/PanModalAnimator.swift +++ b/PanModal/Animator/PanModalAnimator.swift @@ -13,28 +13,29 @@ import UIKit */ struct PanModalAnimator { - /** - Constant Animation Properties - */ - struct Constants { - static let defaultTransitionDuration: TimeInterval = 0.5 + static func makeDefaultAnimator() -> UIViewPropertyAnimator { + // Note that `duration` is ignored when using timing parameters. + // The duration is derived from the parameters. + let animator = UIViewPropertyAnimator(duration: 0, timingParameters: UISpringTimingParameters()) + animator.isUserInteractionEnabled = true + return animator } static func animate(_ animations: @escaping PanModalPresentable.AnimationBlockType, config: PanModalPresentable?, _ completion: PanModalPresentable.AnimationCompletionType? = nil) { - let transitionDuration = config?.transitionDuration ?? Constants.defaultTransitionDuration - let springDamping = config?.springDamping ?? 1.0 - let animationOptions = config?.transitionAnimationOptions ?? [] - - UIView.animate(withDuration: transitionDuration, - delay: 0, - usingSpringWithDamping: springDamping, - initialSpringVelocity: 0, - options: animationOptions, - animations: animations, - completion: completion) + let animator = config?.makeAnimator() ?? makeDefaultAnimator() + + animator.addAnimations(animations) + + if let completion = completion { + animator.addCompletion { position in + completion(position == .end) + } + } + + animator.startAnimation() } } #endif diff --git a/PanModal/Animator/PanModalPresentationAnimator.swift b/PanModal/Animator/PanModalPresentationAnimator.swift index f7fbdd0e..50d2c3f6 100644 --- a/PanModal/Animator/PanModalPresentationAnimator.swift +++ b/PanModal/Animator/PanModalPresentationAnimator.swift @@ -151,9 +151,9 @@ extension PanModalPresentationAnimator: UIViewControllerAnimatedTransitioning { guard let context = transitionContext, let presentable = panModalLayoutType(from: context) - else { return PanModalAnimator.Constants.defaultTransitionDuration } + else { return PanModalAnimator.makeDefaultAnimator().duration } - return presentable.transitionDuration + return presentable.makeAnimator().duration } /** diff --git a/PanModal/Presentable/PanModalPresentable+Defaults.swift b/PanModal/Presentable/PanModalPresentable+Defaults.swift index 76a0679f..f014af70 100644 --- a/PanModal/Presentable/PanModalPresentable+Defaults.swift +++ b/PanModal/Presentable/PanModalPresentable+Defaults.swift @@ -35,18 +35,6 @@ public extension PanModalPresentable where Self: UIViewController { 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 panModalBackgroundColor: UIColor { return UIColor.black.withAlphaComponent(0.7) } @@ -97,6 +85,10 @@ public extension PanModalPresentable where Self: UIViewController { return shouldRoundTopCorners } + func makeAnimator() -> UIViewPropertyAnimator { + PanModalAnimator.makeDefaultAnimator() + } + func shouldRespond(to panModalGestureRecognizer: UIPanGestureRecognizer) -> Bool { return true } diff --git a/PanModal/Presentable/PanModalPresentable.swift b/PanModal/Presentable/PanModalPresentable.swift index 76c15015..56ea0d74 100644 --- a/PanModal/Presentable/PanModalPresentable.swift +++ b/PanModal/Presentable/PanModalPresentable.swift @@ -62,30 +62,6 @@ public protocol PanModalPresentable: AnyObject { */ var cornerRadius: CGFloat { get } - /** - The springDamping value used to determine the amount of 'bounce' - seen when transitioning to short/long form. - - Default Value is 0.8. - */ - 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 color. @@ -173,6 +149,13 @@ public protocol PanModalPresentable: AnyObject { */ var showDragIndicator: Bool { get } + /** + Asks the delegate to create a property animator to use when transitioning to short/long form. + + Default implementation creates an animator with the default UISpringTimingParameters, which matches iOS system animations. + */ + func makeAnimator() -> UIViewPropertyAnimator + /** Asks the delegate if the pan modal should respond to the pan modal gesture recognizer. diff --git a/PanModalDemo.xcodeproj/project.pbxproj b/PanModalDemo.xcodeproj/project.pbxproj index 0fe4e141..ae1ad2d3 100644 --- a/PanModalDemo.xcodeproj/project.pbxproj +++ b/PanModalDemo.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 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 */; }; @@ -23,6 +22,8 @@ 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 */; }; + 27B8DDA725E2F4F9009F9BAA /* PanModalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27B8DDA625E2F4F9009F9BAA /* PanModalAnimator.swift */; }; + 27B8DDAA25E2F6DD009F9BAA /* PanModalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27B8DDA625E2F4F9009F9BAA /* PanModalAnimator.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 */; }; @@ -33,7 +34,6 @@ 743CABC72226171500634A5A /* PanModalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABC62226171500634A5A /* PanModalTests.swift */; }; 743CABD322265F2E00634A5A /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CABD222265F2E00634A5A /* ProfileViewController.swift */; }; 743CB2AA222660D100665A55 /* StackedProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 743CB2A9222660D100665A55 /* StackedProfileViewController.swift */; }; - 74C072A3220BA6E500124CE1 /* PanModalAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A2220BA6E500124CE1 /* PanModalAnimator.swift */; }; 74C072A5220BA76D00124CE1 /* PanModalHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A4220BA76D00124CE1 /* PanModalHeight.swift */; }; 74C072A7220BA78800124CE1 /* PanModalPresentable+LayoutHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A6220BA78800124CE1 /* PanModalPresentable+LayoutHelpers.swift */; }; 74C072AA220BA82A00124CE1 /* UIViewController+PanModalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74C072A9220BA82A00124CE1 /* UIViewController+PanModalPresenter.swift */; }; @@ -93,6 +93,7 @@ 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 = ""; }; 0F2A2C542239C119003BDB2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 27B8DDA625E2F4F9009F9BAA /* PanModalAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalAnimator.swift; sourceTree = ""; }; 743CABAF2225FC9F00634A5A /* UserGroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupViewController.swift; sourceTree = ""; }; 743CABB12225FD1100634A5A /* UserGroupHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupHeaderView.swift; sourceTree = ""; }; 743CABB32225FE7700634A5A /* UserGroupMemberPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserGroupMemberPresentable.swift; sourceTree = ""; }; @@ -105,7 +106,6 @@ 743CABC82226171500634A5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 743CABD222265F2E00634A5A /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; 743CB2A9222660D100665A55 /* StackedProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackedProfileViewController.swift; sourceTree = ""; }; - 74C072A2220BA6E500124CE1 /* PanModalAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanModalAnimator.swift; sourceTree = ""; }; 74C072A4220BA76D00124CE1 /* PanModalHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanModalHeight.swift; sourceTree = ""; }; 74C072A6220BA78800124CE1 /* PanModalPresentable+LayoutHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PanModalPresentable+LayoutHelpers.swift"; sourceTree = ""; }; 74C072A9220BA82A00124CE1 /* UIViewController+PanModalPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+PanModalPresenter.swift"; sourceTree = ""; }; @@ -290,7 +290,7 @@ DC139065216D9458007A3E64 /* Animator */ = { isa = PBXGroup; children = ( - 74C072A2220BA6E500124CE1 /* PanModalAnimator.swift */, + 27B8DDA625E2F4F9009F9BAA /* PanModalAnimator.swift */, DC139066216D9458007A3E64 /* PanModalPresentationAnimator.swift */, ); path = Animator; @@ -531,12 +531,12 @@ 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 */, + 27B8DDA725E2F4F9009F9BAA /* PanModalAnimator.swift in Sources */, 0F2A2C642239C14E003BDB2F /* PanModalPresentable+Defaults.swift in Sources */, 0F2A2C652239C151003BDB2F /* PanModalPresentable+UIViewController.swift in Sources */, 0F2A2C662239C153003BDB2F /* PanModalPresentable+LayoutHelpers.swift in Sources */, @@ -561,13 +561,13 @@ files = ( DC3B2EBA222A560A000C8A4A /* TransientAlertViewController.swift in Sources */, 743CABB42225FE7700634A5A /* UserGroupMemberPresentable.swift in Sources */, - 74C072A3220BA6E500124CE1 /* PanModalAnimator.swift in Sources */, 743CABB8222600C600634A5A /* UserGroupMemberCell.swift in Sources */, 743CABB62225FEEE00634A5A /* UserGroupHeaderPresentable.swift in Sources */, 743CB2AA222660D100665A55 /* StackedProfileViewController.swift in Sources */, 943904EB2226354100859537 /* BasicViewController.swift in Sources */, DC139073216D9458007A3E64 /* PanModalPresenter.swift in Sources */, 943904EF2226383700859537 /* NavigationController.swift in Sources */, + 27B8DDAA25E2F6DD009F9BAA /* PanModalAnimator.swift in Sources */, DC3B2EBE222A58C9000C8A4A /* AlertView.swift in Sources */, 74C072A5220BA76D00124CE1 /* PanModalHeight.swift in Sources */, 94795C9B21F0335D008045A0 /* PanModalPresentationDelegate.swift in Sources */, diff --git a/Sample/View Controllers/Alert/AlertViewController.swift b/Sample/View Controllers/Alert/AlertViewController.swift index 951e3e2b..2b4f3625 100644 --- a/Sample/View Controllers/Alert/AlertViewController.swift +++ b/Sample/View Controllers/Alert/AlertViewController.swift @@ -65,4 +65,10 @@ class AlertViewController: UIViewController, PanModalPresentable { var isUserInteractionEnabled: Bool { return true } + + func makeAnimator() -> UIViewPropertyAnimator { + let animator = UIViewPropertyAnimator(duration: 0.5, dampingRatio: 0.7, animations: nil) + animator.isUserInteractionEnabled = true + return animator + } } diff --git a/Sample/View Controllers/Full Screen/FullScreenNavController.swift b/Sample/View Controllers/Full Screen/FullScreenNavController.swift index 9dbe6215..2537623c 100644 --- a/Sample/View Controllers/Full Screen/FullScreenNavController.swift +++ b/Sample/View Controllers/Full Screen/FullScreenNavController.swift @@ -26,18 +26,6 @@ extension FullScreenNavController: PanModalPresentable { 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 } diff --git a/Tests/PanModalTests.swift b/Tests/PanModalTests.swift index 7652b55f..343e28bc 100644 --- a/Tests/PanModalTests.swift +++ b/Tests/PanModalTests.swift @@ -47,7 +47,6 @@ class PanModalTests: XCTestCase { XCTAssertEqual(vc.topOffset, 41.0) XCTAssertEqual(vc.shortFormHeight, PanModalHeight.maxHeight) XCTAssertEqual(vc.longFormHeight, PanModalHeight.maxHeight) - XCTAssertEqual(vc.springDamping, 0.8) XCTAssertEqual(vc.panModalBackgroundColor, UIColor.black.withAlphaComponent(0.7)) XCTAssertEqual(vc.dragIndicatorBackgroundColor, UIColor.lightGray) XCTAssertEqual(vc.scrollIndicatorInsets, .zero) @@ -61,8 +60,6 @@ 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() { From 914f2c2778bb4973c8ea0f7533b7e94e427cd6ea Mon Sep 17 00:00:00 2001 From: Kyle Bashour Date: Sun, 21 Feb 2021 15:44:32 -0800 Subject: [PATCH 2/2] Add at least some tests --- PanModalDemo.xcodeproj/project.pbxproj | 4 +++ Tests/AnimatorTests.swift | 49 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 Tests/AnimatorTests.swift diff --git a/PanModalDemo.xcodeproj/project.pbxproj b/PanModalDemo.xcodeproj/project.pbxproj index ae1ad2d3..6d89ae72 100644 --- a/PanModalDemo.xcodeproj/project.pbxproj +++ b/PanModalDemo.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 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 */; }; + C256B8A225E326430044BB4D /* AnimatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C256B89C25E3260D0044BB4D /* AnimatorTests.swift */; }; DC13905E216D90D5007A3E64 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC13905D216D90D5007A3E64 /* Assets.xcassets */; }; DC139061216D93ED007A3E64 /* SampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC139060216D93ED007A3E64 /* SampleViewController.swift */; }; DC139070216D9458007A3E64 /* PanModalPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC139066216D9458007A3E64 /* PanModalPresentationAnimator.swift */; }; @@ -116,6 +117,7 @@ 944EBA2D227BB7F400C4C97B /* FullScreenNavController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenNavController.swift; sourceTree = ""; }; 94795C9A21F0335D008045A0 /* PanModalPresentationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalPresentationDelegate.swift; sourceTree = ""; }; 94795C9C21F03368008045A0 /* PanContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanContainerView.swift; sourceTree = ""; }; + C256B89C25E3260D0044BB4D /* AnimatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatorTests.swift; sourceTree = ""; }; DC13905D216D90D5007A3E64 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DC139060216D93ED007A3E64 /* SampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleViewController.swift; sourceTree = ""; }; DC139066216D9458007A3E64 /* PanModalPresentationAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PanModalPresentationAnimator.swift; sourceTree = ""; }; @@ -208,6 +210,7 @@ isa = PBXGroup; children = ( 743CABC62226171500634A5A /* PanModalTests.swift */, + C256B89C25E3260D0044BB4D /* AnimatorTests.swift */, 743CABC82226171500634A5A /* Info.plist */, ); path = Tests; @@ -551,6 +554,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C256B8A225E326430044BB4D /* AnimatorTests.swift in Sources */, 743CABC72226171500634A5A /* PanModalTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/AnimatorTests.swift b/Tests/AnimatorTests.swift new file mode 100644 index 00000000..cd9ff756 --- /dev/null +++ b/Tests/AnimatorTests.swift @@ -0,0 +1,49 @@ +// +// AnimatorTests.swift +// PanModalDemo +// +// Created by Kyle Bashour on 2/21/21. +// Copyright © 2021 Detail. All rights reserved. +// + +import XCTest +@testable import PanModal + +class AnimatorTests: XCTestCase { + + class MockViewController: UIViewController, PanModalPresentable { + let animator = UIViewPropertyAnimator(duration: 0.1, curve: .easeIn, animations: nil) + + var panScrollable: UIScrollView? { + nil + } + + func makeAnimator() -> UIViewPropertyAnimator { + animator + } + } + + func testCustomAnimatorIsUsed() { + let expectation = XCTestExpectation(description: "The custom property animator should be used") + let controller = MockViewController() + + controller.animator.addCompletion { _ in + expectation.fulfill() + } + + PanModalAnimator.animate({}, config: controller) + + wait(for: [expectation], timeout: 1) + } + + func testCompletionIsCalledWithCustomAnimator() { + let expectation = XCTestExpectation(description: "The completion block should be called by the animator") + let controller = MockViewController() + + PanModalAnimator.animate({}, config: controller) { _ in + expectation.fulfill() + } + + wait(for: [expectation], timeout: 1) + } +}