├── .gitignore
├── LICENSE
├── Logo.png
├── Package.swift
├── README.md
├── ResizableController.podspec
├── ResizableController.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ ├── ResizableController.xcscheme
│ └── ResizableControllerUnitTests.xcscheme
├── ResizableController
├── 0.0.1
│ └── ResizableController.podspec
├── Info.plist
├── ResizableAnimatedController.swift
├── ResizableController.h
├── ResizableControllerObserver.swift
├── ResizableTransitioningController.swift
└── UIView+Extension.swift
├── ResizableControllerSample
├── .gitignore
├── LICENSE
├── Podfile
├── README.md
├── ResizableControllerSample.xcodeproj
│ └── project.pbxproj
├── ResizableControllerSample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── FixedHeightPresentedViewController.swift
│ ├── Info.plist
│ ├── PresentingViewController.swift
│ ├── ResizablePresentedViewController.swift
│ └── SceneDelegate.swift
└── ResizableControllerSampleUITests
│ ├── Info.plist
│ └── ResizableControllerSampleUITests.swift
├── ResizableControllerUnitTests
├── Info.plist
└── ResizableControllerUnitTests.swift
└── Sources
└── ResizableController
├── ResizableAnimatedController.swift
├── ResizableControllerObserver.swift
├── ResizableTransitioningController.swift
└── UIView+Extension.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 |
4 | ## Build generated
5 | build/
6 | DerivedData/
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata
18 | xcuserdata/
19 |
20 | ## Workspace file
21 | *.xcworkspace/
22 |
23 | ## Other
24 | *.moved-aside
25 | *.xccheckout
26 | *.xcuserstate
27 | *.xcscmblueprint
28 |
29 | ## Obj-C/Swift specific
30 | *.hmap
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 | *.app.dSYM.zip
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Paytm Money
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paytmmoney/ResizableController/e598e1b0acceb864f82b86a9bd9594989c95deb9/Logo.png
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "ResizableController",
8 | platforms: [
9 | .iOS(.v11)
10 | ],
11 | products: [
12 | // Products define the executables and libraries a package produces, and make them visible to other packages.
13 | .library(
14 | name: "ResizableController",
15 | targets: ["ResizableController"]),
16 | ],
17 | targets: [
18 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
19 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
20 | .target(
21 | name: "ResizableController",
22 | dependencies: []),
23 | .testTarget(
24 | name: "ResizableControllerTests",
25 | dependencies: ["ResizableController"]),
26 | ]
27 | )
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Overview
20 |
21 | **ResizableController** is the custom model presentation style written in swift.
22 |
23 |
24 | | Dark Mode | Light Mode |
25 | |:----------|:-----|
26 | |||
27 | |||
28 |
29 |
30 | ## Features
31 |
32 | - [X] Resizable View Controller with **custom initial/final height.**
33 | - [X] Works on all screens and devices supporting **iOS 11.0+**
34 | - [X] Provides Backward compatibility of iOS 13's automatic presentation style to lower versions.
35 | - [X] 100% compatible with other presentation styles.
36 | - [X] Simple to Integrate, merely couple of lines of code.
37 | - [X] Slick transition animations.
38 | - [X] Dedicated Callbacks when view controller size changes.
39 | - [X] Controller can be dismissed via swipe down and background tap.
40 | - [X] Light and Dark mode compatible.
41 |
42 | ## Installation
43 | This version is Swift 5 compatible.
44 |
45 | ### CocoaPods
46 |
47 | ResizableController is available through [CocoaPods](http://cocoapods.org). To install
48 | it, simply add the following line to your Podfile:
49 |
50 | ```ruby
51 | pod 'ResizableController', '~> 1.0'
52 | ```
53 |
54 | ### Swift Package Manager
55 |
56 | ResizableController is available through [Swift Package Manager](https://swift.org/package-manager/). To install
57 | it, add package dependency from Url:
58 |
59 | ```swift
60 | https://github.com/paytmmoney/ResizableController
61 | ```
62 |
63 | ## Usage
64 | ### ResizableControllerPositionHandler
65 | View Controller to be presented, using resizable transition, needs to conform to protocol `ResizableControllerPositionHandler`. This protocol inherits UIViewController at implementattion level.
66 |
67 | ```swift
68 | public protocol ResizableControllerPositionHandler: UIViewController {
69 | var shouldShowSlideUpIndication: Bool { get }
70 | var sliderBackgroundColor: UIColor { get }
71 |
72 | var initialTopOffset: CGFloat { get }
73 | var finalTopOffset: CGFloat { get }
74 |
75 | func willMoveTopOffset(value: CGFloat)
76 | func didMoveTopOffset(value: CGFloat)
77 | }
78 | ```
79 | All the above properties are optional and can be added to achive different result.
80 |
81 | ### shouldShowSlideUpIndication:
82 |
83 | Override this property if you do not want to include intuitive slide up indicator. Disabled by default for non-resizable views controllers.
84 |
85 | ### sliderBackgroundColor:
86 |
87 | Override this property to give differnent colour to Slider up indicator. Defaults to darkGrey with alpha 0.5
88 |
89 | ### initialTopOffset:
90 |
91 | Override this property to give initial custom height, calculated from top.
92 |
93 | Suggestion: Think about this offset as a topAnchor constraint we apply to a view.
94 |
95 | ### finalTopOffset:
96 |
97 | Override this property to give custom final height, calculated from top. Resizable controller will change its height from initialTopOffset to finalTopOffset.
98 |
99 | ### willMoveTopOffset:
100 |
101 | Override this property to add behaviours to view controller before it changes it size.
102 | If you override this property, make sure you dismiss view controller manually as default behaviur will be overridden.
103 |
104 | ### didMoveTopOffset:
105 | Similar to willMoveTopOffset, but will trigger when animation is complete and view controller is resized.
106 |
107 |
108 | ## Example
109 |
110 | ## Rezisable View Controller
111 |
112 | For creating a resizable controller. Conform to `ResizableControllerPositionHandler` and override `initialTopOffset`.
113 |
114 | ```swift
115 | import ResizableController
116 |
117 | class ResizablePresentedViewController: UIViewController {
118 |
119 | override func viewDidLoad() {
120 | super.viewDidLoad()
121 | }
122 | }
123 |
124 | extension ResizablePresentedViewController: ResizableControllerPositionHandler {
125 | // This height 500 is from topAnchor
126 | var initialTopOffset: CGFloat {
127 | 500
128 | }
129 | }
130 | ```
131 |
132 | ## Fixed Height View Controller
133 |
134 | For creating a fixed height controller. Conform to `ResizableControllerPositionHandler` and override `initialTopOffset` & `finalTopOffset`.
135 |
136 | ```swift
137 | import ResizableController
138 |
139 | class FixedHeightPresentedViewController: UIViewController {
140 |
141 | override func viewDidLoad() {
142 | super.viewDidLoad()
143 | }
144 | }
145 |
146 | extension FixedHeightPresentedViewController: ResizableControllerPositionHandler {
147 | // This height 500 is from topAnchor
148 | var initialTopOffset: CGFloat {
149 | 500
150 | }
151 |
152 | // Both initial and final height should be same to make it a fixed height controller
153 | var finalTopOffset: CGFloat {
154 | 500
155 | }
156 | }
157 | ```
158 |
159 | or:
160 |
161 | Do not override any property, this will give you iOS 13's automatic presentation, which can be used with lower iOS versions.
162 |
163 | ```swift
164 | import ResizableController
165 |
166 | class FixedHeightPresentedViewController: UIViewController {
167 |
168 | override func viewDidLoad() {
169 | super.viewDidLoad()
170 | }
171 | }
172 |
173 | extension ResizablePresentedViewController: ResizableControllerPositionHandler {}
174 | ```
175 |
176 | ## How to modally Present
177 |
178 | To present, call this below overload method
179 |
180 | ```swift
181 | func present(_ viewControllerToPresent: ResizableControllerPositionHandler,
182 | animationDuration: TimeInterval = 0.3,
183 | completion: (() -> Void)? = nil)
184 | ```
185 | Example:
186 |
187 | ```swift
188 | let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ResizablePresentedViewController") as ResizablePresentedViewController
189 | self.present(viewController)
190 | ```
191 |
192 | # Author
193 |
194 |
195 | **Arjun Baru**, iOS Engineer at Paytmoney Ltd, [paytmmoney.com](https://www.paytmmoney.com/)
196 | You can reach out to me at **arjun.baru@paytmmoney.com**
197 |
198 | In collaboration with:
199 |
200 | [Shahrukh Alam](https://github.com/shahrukh-alam) & [Rahul Mathur](https://github.com/PaytmMoneyOpenSource)
201 |
202 |
203 | # License
204 |
205 | ResizableController is available under the MIT license. See the LICENSE file for more info.
206 |
207 | ## Sample Project
208 |
209 | Here is the sample project implementing ResizableController [Sample Project](https://github.com/paytmmoney/ResizableController/tree/main)
210 |
211 |
212 | ## Suggestions or feedback?
213 |
214 | Feel free to create a pull request, open an issue or find [us on Twitter](https://twitter.com/PaytmMoney).
215 |
216 |
--------------------------------------------------------------------------------
/ResizableController.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint ResizableController.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |spec|
10 |
11 | spec.name = "ResizableController"
12 | spec.version = "1.0.0"
13 | spec.summary = "ResizableController for Custom Model Presentation"
14 | spec.description = "A Custom Presentation which acts as a custom-sizing view as well as full presented view. While doing this presentation, it manages to render background view which gives the view hierarchy, a nice 3D effect. Check screenshot for more details."
15 |
16 | spec.source_files = "ResizableController/**/*.{swift,h}"
17 | spec.homepage = "https://github.com/paytmmoney/ResizableController"
18 | spec.source = { :git => "https://github.com/paytmmoney/ResizableController.git",
19 | :tag => '1.0.0' }
20 |
21 | spec.license = { :type => "MIT", :file => "LICENSE" }
22 |
23 | spec.author = { "Arjun Baru" => "arjun.baru@paytmmoney.com" }
24 |
25 | spec.platform = :ios, "11.0"
26 | spec.swift_version = "5"
27 | end
28 |
--------------------------------------------------------------------------------
/ResizableController.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 420FF919254155C2000FEDAD /* ResizableController.h in Headers */ = {isa = PBXBuildFile; fileRef = 420FF917254155C2000FEDAD /* ResizableController.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 420FF921254157C4000FEDAD /* ResizableControllerObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420FF920254157C3000FEDAD /* ResizableControllerObserver.swift */; };
12 | 420FF924254157DB000FEDAD /* ResizableTransitioningController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420FF923254157DB000FEDAD /* ResizableTransitioningController.swift */; };
13 | 420FF927254157EC000FEDAD /* ResizableAnimatedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420FF926254157EC000FEDAD /* ResizableAnimatedController.swift */; };
14 | 420FF92A25417524000FEDAD /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420FF92925417524000FEDAD /* UIView+Extension.swift */; };
15 | 42EFACA7255AC2B3000CB6BC /* ResizableControllerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EFACA6255AC2B3000CB6BC /* ResizableControllerUnitTests.swift */; };
16 | 42EFACA9255AC2B3000CB6BC /* ResizableController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 420FF914254155C2000FEDAD /* ResizableController.framework */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXContainerItemProxy section */
20 | 42EFACAA255AC2B3000CB6BC /* PBXContainerItemProxy */ = {
21 | isa = PBXContainerItemProxy;
22 | containerPortal = 420FF90B254155C2000FEDAD /* Project object */;
23 | proxyType = 1;
24 | remoteGlobalIDString = 420FF913254155C2000FEDAD;
25 | remoteInfo = ResizableController;
26 | };
27 | /* End PBXContainerItemProxy section */
28 |
29 | /* Begin PBXFileReference section */
30 | 420FF914254155C2000FEDAD /* ResizableController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ResizableController.framework; sourceTree = BUILT_PRODUCTS_DIR; };
31 | 420FF917254155C2000FEDAD /* ResizableController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ResizableController.h; sourceTree = ""; };
32 | 420FF918254155C2000FEDAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
33 | 420FF920254157C3000FEDAD /* ResizableControllerObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizableControllerObserver.swift; sourceTree = ""; };
34 | 420FF923254157DB000FEDAD /* ResizableTransitioningController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizableTransitioningController.swift; sourceTree = ""; };
35 | 420FF926254157EC000FEDAD /* ResizableAnimatedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResizableAnimatedController.swift; sourceTree = ""; };
36 | 420FF92925417524000FEDAD /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; };
37 | 42EFACA4255AC2B3000CB6BC /* ResizableControllerUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResizableControllerUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
38 | 42EFACA6255AC2B3000CB6BC /* ResizableControllerUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizableControllerUnitTests.swift; sourceTree = ""; };
39 | 42EFACA8255AC2B3000CB6BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
40 | /* End PBXFileReference section */
41 |
42 | /* Begin PBXFrameworksBuildPhase section */
43 | 420FF911254155C2000FEDAD /* Frameworks */ = {
44 | isa = PBXFrameworksBuildPhase;
45 | buildActionMask = 2147483647;
46 | files = (
47 | );
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | 42EFACA1255AC2B3000CB6BC /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | 42EFACA9255AC2B3000CB6BC /* ResizableController.framework in Frameworks */,
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | /* End PBXFrameworksBuildPhase section */
59 |
60 | /* Begin PBXGroup section */
61 | 420FF90A254155C2000FEDAD = {
62 | isa = PBXGroup;
63 | children = (
64 | 420FF916254155C2000FEDAD /* ResizableController */,
65 | 42EFACA5255AC2B3000CB6BC /* ResizableControllerUnitTests */,
66 | 420FF915254155C2000FEDAD /* Products */,
67 | );
68 | sourceTree = "";
69 | };
70 | 420FF915254155C2000FEDAD /* Products */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 420FF914254155C2000FEDAD /* ResizableController.framework */,
74 | 42EFACA4255AC2B3000CB6BC /* ResizableControllerUnitTests.xctest */,
75 | );
76 | name = Products;
77 | sourceTree = "";
78 | };
79 | 420FF916254155C2000FEDAD /* ResizableController */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 420FF926254157EC000FEDAD /* ResizableAnimatedController.swift */,
83 | 420FF923254157DB000FEDAD /* ResizableTransitioningController.swift */,
84 | 420FF92925417524000FEDAD /* UIView+Extension.swift */,
85 | 420FF920254157C3000FEDAD /* ResizableControllerObserver.swift */,
86 | 420FF917254155C2000FEDAD /* ResizableController.h */,
87 | 420FF918254155C2000FEDAD /* Info.plist */,
88 | );
89 | path = ResizableController;
90 | sourceTree = "";
91 | };
92 | 42EFACA5255AC2B3000CB6BC /* ResizableControllerUnitTests */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 42EFACA6255AC2B3000CB6BC /* ResizableControllerUnitTests.swift */,
96 | 42EFACA8255AC2B3000CB6BC /* Info.plist */,
97 | );
98 | path = ResizableControllerUnitTests;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXHeadersBuildPhase section */
104 | 420FF90F254155C2000FEDAD /* Headers */ = {
105 | isa = PBXHeadersBuildPhase;
106 | buildActionMask = 2147483647;
107 | files = (
108 | 420FF919254155C2000FEDAD /* ResizableController.h in Headers */,
109 | );
110 | runOnlyForDeploymentPostprocessing = 0;
111 | };
112 | /* End PBXHeadersBuildPhase section */
113 |
114 | /* Begin PBXNativeTarget section */
115 | 420FF913254155C2000FEDAD /* ResizableController */ = {
116 | isa = PBXNativeTarget;
117 | buildConfigurationList = 420FF91C254155C2000FEDAD /* Build configuration list for PBXNativeTarget "ResizableController" */;
118 | buildPhases = (
119 | 420FF90F254155C2000FEDAD /* Headers */,
120 | 420FF910254155C2000FEDAD /* Sources */,
121 | 420FF911254155C2000FEDAD /* Frameworks */,
122 | 420FF912254155C2000FEDAD /* Resources */,
123 | );
124 | buildRules = (
125 | );
126 | dependencies = (
127 | );
128 | name = ResizableController;
129 | productName = ResizableController;
130 | productReference = 420FF914254155C2000FEDAD /* ResizableController.framework */;
131 | productType = "com.apple.product-type.framework";
132 | };
133 | 42EFACA3255AC2B3000CB6BC /* ResizableControllerUnitTests */ = {
134 | isa = PBXNativeTarget;
135 | buildConfigurationList = 42EFACAC255AC2B3000CB6BC /* Build configuration list for PBXNativeTarget "ResizableControllerUnitTests" */;
136 | buildPhases = (
137 | 42EFACA0255AC2B3000CB6BC /* Sources */,
138 | 42EFACA1255AC2B3000CB6BC /* Frameworks */,
139 | 42EFACA2255AC2B3000CB6BC /* Resources */,
140 | );
141 | buildRules = (
142 | );
143 | dependencies = (
144 | 42EFACAB255AC2B3000CB6BC /* PBXTargetDependency */,
145 | );
146 | name = ResizableControllerUnitTests;
147 | productName = ResizableControllerUnitTests;
148 | productReference = 42EFACA4255AC2B3000CB6BC /* ResizableControllerUnitTests.xctest */;
149 | productType = "com.apple.product-type.bundle.unit-test";
150 | };
151 | /* End PBXNativeTarget section */
152 |
153 | /* Begin PBXProject section */
154 | 420FF90B254155C2000FEDAD /* Project object */ = {
155 | isa = PBXProject;
156 | attributes = {
157 | LastSwiftUpdateCheck = 1200;
158 | LastUpgradeCheck = 1200;
159 | TargetAttributes = {
160 | 420FF913254155C2000FEDAD = {
161 | CreatedOnToolsVersion = 12.0.1;
162 | LastSwiftMigration = 1200;
163 | };
164 | 42EFACA3255AC2B3000CB6BC = {
165 | CreatedOnToolsVersion = 12.0.1;
166 | };
167 | };
168 | };
169 | buildConfigurationList = 420FF90E254155C2000FEDAD /* Build configuration list for PBXProject "ResizableController" */;
170 | compatibilityVersion = "Xcode 9.3";
171 | developmentRegion = en;
172 | hasScannedForEncodings = 0;
173 | knownRegions = (
174 | en,
175 | Base,
176 | );
177 | mainGroup = 420FF90A254155C2000FEDAD;
178 | productRefGroup = 420FF915254155C2000FEDAD /* Products */;
179 | projectDirPath = "";
180 | projectRoot = "";
181 | targets = (
182 | 420FF913254155C2000FEDAD /* ResizableController */,
183 | 42EFACA3255AC2B3000CB6BC /* ResizableControllerUnitTests */,
184 | );
185 | };
186 | /* End PBXProject section */
187 |
188 | /* Begin PBXResourcesBuildPhase section */
189 | 420FF912254155C2000FEDAD /* Resources */ = {
190 | isa = PBXResourcesBuildPhase;
191 | buildActionMask = 2147483647;
192 | files = (
193 | );
194 | runOnlyForDeploymentPostprocessing = 0;
195 | };
196 | 42EFACA2255AC2B3000CB6BC /* Resources */ = {
197 | isa = PBXResourcesBuildPhase;
198 | buildActionMask = 2147483647;
199 | files = (
200 | );
201 | runOnlyForDeploymentPostprocessing = 0;
202 | };
203 | /* End PBXResourcesBuildPhase section */
204 |
205 | /* Begin PBXSourcesBuildPhase section */
206 | 420FF910254155C2000FEDAD /* Sources */ = {
207 | isa = PBXSourcesBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | 420FF927254157EC000FEDAD /* ResizableAnimatedController.swift in Sources */,
211 | 420FF921254157C4000FEDAD /* ResizableControllerObserver.swift in Sources */,
212 | 420FF92A25417524000FEDAD /* UIView+Extension.swift in Sources */,
213 | 420FF924254157DB000FEDAD /* ResizableTransitioningController.swift in Sources */,
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | 42EFACA0255AC2B3000CB6BC /* Sources */ = {
218 | isa = PBXSourcesBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | 42EFACA7255AC2B3000CB6BC /* ResizableControllerUnitTests.swift in Sources */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | /* End PBXSourcesBuildPhase section */
226 |
227 | /* Begin PBXTargetDependency section */
228 | 42EFACAB255AC2B3000CB6BC /* PBXTargetDependency */ = {
229 | isa = PBXTargetDependency;
230 | target = 420FF913254155C2000FEDAD /* ResizableController */;
231 | targetProxy = 42EFACAA255AC2B3000CB6BC /* PBXContainerItemProxy */;
232 | };
233 | /* End PBXTargetDependency section */
234 |
235 | /* Begin XCBuildConfiguration section */
236 | 420FF91A254155C2000FEDAD /* Debug */ = {
237 | isa = XCBuildConfiguration;
238 | buildSettings = {
239 | ALWAYS_SEARCH_USER_PATHS = NO;
240 | CLANG_ANALYZER_NONNULL = YES;
241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
243 | CLANG_CXX_LIBRARY = "libc++";
244 | CLANG_ENABLE_MODULES = YES;
245 | CLANG_ENABLE_OBJC_ARC = YES;
246 | CLANG_ENABLE_OBJC_WEAK = YES;
247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
248 | CLANG_WARN_BOOL_CONVERSION = YES;
249 | CLANG_WARN_COMMA = YES;
250 | CLANG_WARN_CONSTANT_CONVERSION = YES;
251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
254 | CLANG_WARN_EMPTY_BODY = YES;
255 | CLANG_WARN_ENUM_CONVERSION = YES;
256 | CLANG_WARN_INFINITE_RECURSION = YES;
257 | CLANG_WARN_INT_CONVERSION = YES;
258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
262 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
263 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
264 | CLANG_WARN_STRICT_PROTOTYPES = YES;
265 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
266 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
267 | CLANG_WARN_UNREACHABLE_CODE = YES;
268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
269 | COPY_PHASE_STRIP = NO;
270 | CURRENT_PROJECT_VERSION = 1;
271 | DEBUG_INFORMATION_FORMAT = dwarf;
272 | ENABLE_STRICT_OBJC_MSGSEND = YES;
273 | ENABLE_TESTABILITY = YES;
274 | GCC_C_LANGUAGE_STANDARD = gnu11;
275 | GCC_DYNAMIC_NO_PIC = NO;
276 | GCC_NO_COMMON_BLOCKS = YES;
277 | GCC_OPTIMIZATION_LEVEL = 0;
278 | GCC_PREPROCESSOR_DEFINITIONS = (
279 | "DEBUG=1",
280 | "$(inherited)",
281 | );
282 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
283 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
284 | GCC_WARN_UNDECLARED_SELECTOR = YES;
285 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
286 | GCC_WARN_UNUSED_FUNCTION = YES;
287 | GCC_WARN_UNUSED_VARIABLE = YES;
288 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
289 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
290 | MTL_FAST_MATH = YES;
291 | ONLY_ACTIVE_ARCH = YES;
292 | SDKROOT = iphoneos;
293 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
294 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
295 | VERSIONING_SYSTEM = "apple-generic";
296 | VERSION_INFO_PREFIX = "";
297 | };
298 | name = Debug;
299 | };
300 | 420FF91B254155C2000FEDAD /* Release */ = {
301 | isa = XCBuildConfiguration;
302 | buildSettings = {
303 | ALWAYS_SEARCH_USER_PATHS = NO;
304 | CLANG_ANALYZER_NONNULL = YES;
305 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
307 | CLANG_CXX_LIBRARY = "libc++";
308 | CLANG_ENABLE_MODULES = YES;
309 | CLANG_ENABLE_OBJC_ARC = YES;
310 | CLANG_ENABLE_OBJC_WEAK = YES;
311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
312 | CLANG_WARN_BOOL_CONVERSION = YES;
313 | CLANG_WARN_COMMA = YES;
314 | CLANG_WARN_CONSTANT_CONVERSION = YES;
315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
317 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
318 | CLANG_WARN_EMPTY_BODY = YES;
319 | CLANG_WARN_ENUM_CONVERSION = YES;
320 | CLANG_WARN_INFINITE_RECURSION = YES;
321 | CLANG_WARN_INT_CONVERSION = YES;
322 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
324 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
326 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
327 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
328 | CLANG_WARN_STRICT_PROTOTYPES = YES;
329 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
330 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
331 | CLANG_WARN_UNREACHABLE_CODE = YES;
332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
333 | COPY_PHASE_STRIP = NO;
334 | CURRENT_PROJECT_VERSION = 1;
335 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
336 | ENABLE_NS_ASSERTIONS = NO;
337 | ENABLE_STRICT_OBJC_MSGSEND = YES;
338 | GCC_C_LANGUAGE_STANDARD = gnu11;
339 | GCC_NO_COMMON_BLOCKS = YES;
340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
342 | GCC_WARN_UNDECLARED_SELECTOR = YES;
343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
344 | GCC_WARN_UNUSED_FUNCTION = YES;
345 | GCC_WARN_UNUSED_VARIABLE = YES;
346 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
347 | MTL_ENABLE_DEBUG_INFO = NO;
348 | MTL_FAST_MATH = YES;
349 | SDKROOT = iphoneos;
350 | SWIFT_COMPILATION_MODE = wholemodule;
351 | SWIFT_OPTIMIZATION_LEVEL = "-O";
352 | VALIDATE_PRODUCT = YES;
353 | VERSIONING_SYSTEM = "apple-generic";
354 | VERSION_INFO_PREFIX = "";
355 | };
356 | name = Release;
357 | };
358 | 420FF91D254155C2000FEDAD /* Debug */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | CLANG_ENABLE_MODULES = YES;
362 | CODE_SIGN_STYLE = Automatic;
363 | DEFINES_MODULE = YES;
364 | DEVELOPMENT_TEAM = 885LR8YVNT;
365 | DYLIB_COMPATIBILITY_VERSION = 1;
366 | DYLIB_CURRENT_VERSION = 1;
367 | DYLIB_INSTALL_NAME_BASE = "@rpath";
368 | INFOPLIST_FILE = ResizableController/Info.plist;
369 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
370 | LD_RUNPATH_SEARCH_PATHS = (
371 | "$(inherited)",
372 | "@executable_path/Frameworks",
373 | "@loader_path/Frameworks",
374 | );
375 | MARKETING_VERSION = 1.0;
376 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.ResizableController;
377 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
378 | SKIP_INSTALL = YES;
379 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
380 | SWIFT_VERSION = 5.0;
381 | TARGETED_DEVICE_FAMILY = "1,2";
382 | };
383 | name = Debug;
384 | };
385 | 420FF91E254155C2000FEDAD /* Release */ = {
386 | isa = XCBuildConfiguration;
387 | buildSettings = {
388 | CLANG_ENABLE_MODULES = YES;
389 | CODE_SIGN_STYLE = Automatic;
390 | DEFINES_MODULE = YES;
391 | DEVELOPMENT_TEAM = 885LR8YVNT;
392 | DYLIB_COMPATIBILITY_VERSION = 1;
393 | DYLIB_CURRENT_VERSION = 1;
394 | DYLIB_INSTALL_NAME_BASE = "@rpath";
395 | INFOPLIST_FILE = ResizableController/Info.plist;
396 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
397 | LD_RUNPATH_SEARCH_PATHS = (
398 | "$(inherited)",
399 | "@executable_path/Frameworks",
400 | "@loader_path/Frameworks",
401 | );
402 | MARKETING_VERSION = 1.0;
403 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.ResizableController;
404 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
405 | SKIP_INSTALL = YES;
406 | SWIFT_VERSION = 5.0;
407 | TARGETED_DEVICE_FAMILY = "1,2";
408 | };
409 | name = Release;
410 | };
411 | 42EFACAD255AC2B3000CB6BC /* Debug */ = {
412 | isa = XCBuildConfiguration;
413 | buildSettings = {
414 | CODE_SIGN_STYLE = Automatic;
415 | DEVELOPMENT_TEAM = V83QP83683;
416 | INFOPLIST_FILE = ResizableControllerUnitTests/Info.plist;
417 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
418 | LD_RUNPATH_SEARCH_PATHS = (
419 | "$(inherited)",
420 | "@executable_path/Frameworks",
421 | "@loader_path/Frameworks",
422 | );
423 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerUnitTests;
424 | PRODUCT_NAME = "$(TARGET_NAME)";
425 | SWIFT_VERSION = 5.0;
426 | TARGETED_DEVICE_FAMILY = "1,2";
427 | };
428 | name = Debug;
429 | };
430 | 42EFACAE255AC2B3000CB6BC /* Release */ = {
431 | isa = XCBuildConfiguration;
432 | buildSettings = {
433 | CODE_SIGN_STYLE = Automatic;
434 | DEVELOPMENT_TEAM = V83QP83683;
435 | INFOPLIST_FILE = ResizableControllerUnitTests/Info.plist;
436 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
437 | LD_RUNPATH_SEARCH_PATHS = (
438 | "$(inherited)",
439 | "@executable_path/Frameworks",
440 | "@loader_path/Frameworks",
441 | );
442 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerUnitTests;
443 | PRODUCT_NAME = "$(TARGET_NAME)";
444 | SWIFT_VERSION = 5.0;
445 | TARGETED_DEVICE_FAMILY = "1,2";
446 | };
447 | name = Release;
448 | };
449 | /* End XCBuildConfiguration section */
450 |
451 | /* Begin XCConfigurationList section */
452 | 420FF90E254155C2000FEDAD /* Build configuration list for PBXProject "ResizableController" */ = {
453 | isa = XCConfigurationList;
454 | buildConfigurations = (
455 | 420FF91A254155C2000FEDAD /* Debug */,
456 | 420FF91B254155C2000FEDAD /* Release */,
457 | );
458 | defaultConfigurationIsVisible = 0;
459 | defaultConfigurationName = Release;
460 | };
461 | 420FF91C254155C2000FEDAD /* Build configuration list for PBXNativeTarget "ResizableController" */ = {
462 | isa = XCConfigurationList;
463 | buildConfigurations = (
464 | 420FF91D254155C2000FEDAD /* Debug */,
465 | 420FF91E254155C2000FEDAD /* Release */,
466 | );
467 | defaultConfigurationIsVisible = 0;
468 | defaultConfigurationName = Release;
469 | };
470 | 42EFACAC255AC2B3000CB6BC /* Build configuration list for PBXNativeTarget "ResizableControllerUnitTests" */ = {
471 | isa = XCConfigurationList;
472 | buildConfigurations = (
473 | 42EFACAD255AC2B3000CB6BC /* Debug */,
474 | 42EFACAE255AC2B3000CB6BC /* Release */,
475 | );
476 | defaultConfigurationIsVisible = 0;
477 | defaultConfigurationName = Release;
478 | };
479 | /* End XCConfigurationList section */
480 | };
481 | rootObject = 420FF90B254155C2000FEDAD /* Project object */;
482 | }
483 |
--------------------------------------------------------------------------------
/ResizableController.xcodeproj/xcshareddata/xcschemes/ResizableController.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/ResizableController.xcodeproj/xcshareddata/xcschemes/ResizableControllerUnitTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
63 |
64 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/ResizableController/0.0.1/ResizableController.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint ResizableController.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |spec|
10 |
11 | spec.name = "ResizableController"
12 | spec.version = "0.0.1"
13 | spec.summary = "ResizableController for Custom Model Presentation"
14 | spec.description = <<-DESC
15 | A Custom Presentation which acts as a custom-sizing view as well as full presented view. While doing this presentation, it manages to render background view which gives the view hierarchy, a nice 3D effect. Check screenshot for more details.
16 | DESC
17 |
18 | spec.source_files = "ResizableController/**/*.{swift,h}"
19 | spec.homepage = "https://rupee.paytmmoney.com/ios/ResizableController"
20 | spec.source = { :git => "git@github.com:paytmmoney/ResizableController.git",
21 | :branch => 'dev/0.1' }
22 |
23 | spec.license = { :type => "MIT", :file => "LICENSE" }
24 |
25 | spec.author = { "Arjun Baru" => "arjun.baru@paytmmoney.com" }
26 | spec.social_media_url = "https://linkedin.com/in/arjun-baru-800785111"
27 |
28 | spec.platform = :ios, "11.0"
29 | spec.swift_version = "5"
30 | end
31 |
--------------------------------------------------------------------------------
/ResizableController/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ResizableController/ResizableAnimatedController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableAnimatedController.swift
3 | //
4 | // Created by Arjun Baru on 25/04/20.
5 | // Copyright © 2020 Paytm Money 🚀. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Handles presentation cases for all type of presentation
11 | enum PresentingViewType {
12 | case custom, `default`, none
13 | }
14 |
15 | /// Manages scaling for presenting view controller
16 | enum ViewControlerScale {
17 | case backgroundPopUpScale
18 | case backgroundFullScreenScale
19 | case reset
20 |
21 | var transform: CATransform3D {
22 | switch self {
23 | case .backgroundPopUpScale:
24 | return CATransform3DMakeScale(0.92, 0.92, 1)
25 | case .backgroundFullScreenScale:
26 | return CATransform3DMakeScale(0.86, 0.86, 1)
27 | case .reset:
28 | return CATransform3DMakeScale(1, 1, 1)
29 | }
30 | }
31 | }
32 |
33 | /// Provides transitionContext for view controller's custom presentation
34 | class ResizableAnimatedController: NSObject {
35 |
36 | let initialTopOffset: CGFloat
37 | var estimatedFinalTopOffset: CGFloat
38 | let animationDuration: TimeInterval
39 | var isPresenting: Bool
40 |
41 | private var presntingViewControlerMinY: CGFloat?
42 | private weak var viewToBeDismissed: UIViewController?
43 | private let tapGesture = UITapGestureRecognizer()
44 |
45 | private lazy var dimmingView: UIView = {
46 | let view = UIView()
47 | view.isOpaque = false
48 | view.addGestureRecognizer(tapGesture)
49 | tapGesture.addTarget(self, action: #selector(onTapOfDimmingView))
50 | view.backgroundColor = UIColor.black
51 | view.alpha = 0
52 | return view
53 | }()
54 |
55 | init?(initialTopOffset: CGFloat,
56 | animationDuration: TimeInterval,
57 | isPresenting: Bool,
58 | estimatedFinalTopOffset: CGFloat) {
59 |
60 | guard initialTopOffset >= ResizableConstants.maximumTopOffset else { return nil }
61 |
62 | self.animationDuration = animationDuration
63 | self.initialTopOffset = initialTopOffset
64 | self.isPresenting = isPresenting
65 | self.estimatedFinalTopOffset = estimatedFinalTopOffset
66 | }
67 |
68 | @objc func onTapOfDimmingView() {
69 | viewToBeDismissed?.dismiss(animated: true, completion: nil)
70 | }
71 |
72 | }
73 |
74 | // MARK: Transitioning Delegate Implementation
75 | extension ResizableAnimatedController: UIViewControllerAnimatedTransitioning {
76 |
77 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
78 | return animationDuration
79 | }
80 |
81 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
82 | guard let fromVC = transitionContext.viewController(forKey: .from),
83 | let toVC = transitionContext.viewController(forKey: .to) else { return }
84 |
85 | let containerView = transitionContext.containerView
86 |
87 | if isPresenting {
88 | viewToBeDismissed = toVC
89 |
90 | toVC.view.frame = CGRect(x: 0.0, y: fromVC.view.frame.maxY,
91 | width: UIScreen.main.bounds.width,
92 | height: UIScreen.main.bounds.height - estimatedFinalTopOffset)
93 |
94 | containerView.addSubview(dimmingView)
95 | dimmingView.edgesToSuperView()
96 | containerView.addSubview(toVC.view)
97 |
98 | toVC.setupViewCorners(radius: 12)
99 | fromVC.setupViewCorners(radius: 12)
100 |
101 | fromVC.beginAppearanceTransition(false, animated: true)
102 | toVC.beginAppearanceTransition(true, animated: true)
103 | toVC.modalPresentationCapturesStatusBarAppearance = true
104 |
105 | UIView.animate(withDuration: animationDuration, animations: {
106 | toVC.view.frame.origin.y = self.initialTopOffset
107 | fromVC.view.layer.transform = ViewControlerScale.backgroundPopUpScale.transform
108 | self.dimmingView.alpha = 0.2
109 | }, completion: { _ in
110 | self.presntingViewControlerMinY = fromVC.view.frame.minY
111 | fromVC.endAppearanceTransition()
112 | toVC.endAppearanceTransition()
113 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
114 | })
115 | } else {
116 | containerView.addSubview(fromVC.view)
117 |
118 | fromVC.beginAppearanceTransition(false, animated: true)
119 | toVC.beginAppearanceTransition(true, animated: true)
120 | UIView.animate(withDuration: animationDuration, animations: {
121 | fromVC.view.frame.origin.y = UIScreen.main.bounds.maxY
122 | self.dimmingView.alpha = 0
123 | switch toVC.viewPresentationStyle() {
124 | case .custom, .default:
125 | toVC.view.frame.origin.y = self.presntingViewControlerMinY ?? 0
126 | toVC.view.layer.transform = ViewControlerScale.reset.transform
127 | case .none:
128 | toVC.view.layer.transform = ViewControlerScale.reset.transform
129 | toVC.view.roundedCorners(withRadius: 0)
130 | }
131 | }, completion: { _ in
132 | fromVC.endAppearanceTransition()
133 | toVC.endAppearanceTransition()
134 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
135 | })
136 | }
137 | }
138 | }
139 |
140 | // MARK: Helper extension of UIViewController
141 | extension UIViewController {
142 | func viewPresentationStyle() -> PresentingViewType {
143 | if self.modalPresentationStyle == .custom {
144 | return .custom
145 | } else if self.presentingViewController != nil && self.modalPresentationStyle != .custom {
146 | return .default
147 | } else {
148 | return .none
149 | }
150 | }
151 |
152 | func setupViewCorners(radius: CGFloat) {
153 | view.roundedCorners(withRadius: 12)
154 | view.clipsToBounds = true
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/ResizableController/ResizableController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableController.h
3 | // ResizableController
4 | //
5 | // Created by Arjun Baru on 22/10/20.
6 | // Copyright © 2020 Paytm Money 🚀. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ResizableController.
12 | FOUNDATION_EXPORT double ResizableControllerVersionNumber;
13 |
14 | //! Project version string for ResizableController.
15 | FOUNDATION_EXPORT const unsigned char ResizableControllerVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ResizableController/ResizableControllerObserver.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableControllerObserver.swift
3 | //
4 | // Created by Arjun Baru on 05/05/20.
5 | // Copyright © 2020 Paytm Money 🚀. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Protocol to integrate Resizable Controller model presentation. To be conformed by the modally presented controller
11 | public protocol ResizableControllerPositionHandler: UIViewController {
12 |
13 | /// Override this property if you do not want to include intuitive slide up indicator. Disabled by default for non-resizable views controllers.
14 | var shouldShowSlideUpIndication: Bool { get }
15 |
16 | /// Override this property to give differnent colour to Slider up indicator. Defaults to darkGrey with alpha 0.5
17 | var sliderBackgroundColor: UIColor { get }
18 |
19 | /// Override this property to give initial custom height, calculated from top.
20 | var initialTopOffset: CGFloat { get }
21 |
22 | /// Override this property to give custom final height, calculated from top. Resizable controller will change its height from initialTopOffset to finalTopOffset.
23 | var finalTopOffset: CGFloat { get }
24 |
25 | /// Override this property to add behaviours to view controller before it changes it size.
26 | /// - Parameter value: new top offset to which view controller will shifted position.
27 | func willMoveTopOffset(value: CGFloat)
28 |
29 | /// Override this property to add additional behaviours to view controller after it changes it size.
30 | /// - Parameter value: new top offset after view controller has shifted position
31 | func didMoveTopOffset(value: CGFloat)
32 | }
33 |
34 |
35 | extension ResizableControllerPositionHandler {
36 | var onView: UIView {
37 | return self.view
38 | }
39 | }
40 |
41 | // MARK: Public default Implementation for protocol
42 |
43 | public extension ResizableControllerPositionHandler {
44 |
45 | func willMoveTopOffset(value: CGFloat) {
46 | if initialTopOffset == finalTopOffset || value > initialTopOffset {
47 | self.dismiss(animated: true, completion: nil)
48 | }
49 | }
50 |
51 | var sliderBackgroundColor: UIColor {
52 | UIColor.darkGray.withAlphaComponent(0.5)
53 | }
54 |
55 | var initialTopOffset: CGFloat {
56 | return ResizableConstants.maximumTopOffset
57 | }
58 |
59 | var finalTopOffset: CGFloat {
60 | return ResizableConstants.maximumTopOffset
61 | }
62 |
63 | var shouldShowSlideUpIndication: Bool {
64 | return initialTopOffset != finalTopOffset
65 | }
66 |
67 | func didMoveTopOffset(value: CGFloat) {}
68 | }
69 |
70 |
71 | /// This class is responsible for handling swipe related recoganisation.
72 | /// It provides call backs on to ResizableControllerPositionHandler protocol conformed class once user interacts with the view controller.
73 | /// Refer to ResizableControllerPositionHandler to see what observations can be subscibed
74 | class ResizableControllerObserver: NSObject, UIGestureRecognizerDelegate, UIScrollViewDelegate {
75 |
76 | private let panGesture = UIPanGestureRecognizer()
77 | private var viewPosition: SliderPosition = .present
78 |
79 | private weak var view: UIView?
80 | private let animationDuration: TimeInterval
81 |
82 | weak var delegate: ResizableControllerPositionHandler?
83 | weak var presentingVC: UIViewController?
84 |
85 | var estimatedFinalTopOffset = UIScreen.main.bounds.height * 0.08
86 | var estimatedInitialTopOffset = UIScreen.main.bounds.height * 0.55
87 | var presentingVCminY: CGFloat = 0
88 | private var gestureDidEndedState = true
89 |
90 | private lazy var slideIndicativeView: UIView = {
91 | let view = UIView()
92 | view.backgroundColor = delegate?.sliderBackgroundColor
93 | view.widthAnchor.constraint(equalToConstant: 55).isActive = true
94 | view.heightAnchor.constraint(equalToConstant: 5).isActive = true
95 | view.layer.cornerRadius = 2
96 | view.translatesAutoresizingMaskIntoConstraints = false
97 | return view
98 | }()
99 |
100 | init(in view: UIView, duration: TimeInterval = 0.3, delegate: ResizableControllerPositionHandler? = nil) {
101 | self.view = view
102 | self.animationDuration = duration
103 | super.init()
104 |
105 | setupDelegate(delegate)
106 | commonInit()
107 | }
108 |
109 | private func commonInit() {
110 | setupGestureRecoganisers()
111 | addSliderView()
112 | }
113 |
114 | private func setupGestureRecoganisers() {
115 | guard let view = view else { return }
116 | self.panGesture.addTarget(self, action: #selector(handlePan))
117 | self.panGesture.delegate = self
118 | view.addGestureRecognizer(panGesture)
119 | }
120 |
121 | fileprivate func setupDelegate(_ delegate: ResizableControllerPositionHandler?) {
122 | self.delegate = delegate
123 |
124 | self.estimatedFinalTopOffset = delegate?.finalTopOffset ?? ResizableConstants.maximumTopOffset
125 | self.estimatedInitialTopOffset = delegate?.initialTopOffset ?? ResizableConstants.maximumTopOffset
126 | }
127 |
128 |
129 | /// handles user's swipe interactions
130 | @objc private func handlePan(_ gestureRecognizer: UIGestureRecognizer) {
131 |
132 | guard let currentView = panGesture.view,
133 | gestureRecognizer == panGesture,
134 | let _ = view else { return }
135 |
136 | switch panGesture.state {
137 | case .changed:
138 | guard gestureDidEndedState else { return }
139 | switch panGesture.dragDirection(inView: currentView) {
140 | case .upwards where !isHeightEqualToEstimatedHeight:
141 | translate(value: estimatedFinalTopOffset)
142 | case .downwards where isHeightEqualToEstimatedHeight:
143 | translate(value: estimatedInitialTopOffset)
144 | case .downwards:
145 | delegate?.willMoveTopOffset(value: UIScreen.main.bounds.maxY)
146 | delegate?.didMoveTopOffset(value: UIScreen.main.bounds.maxY)
147 | default:
148 | break
149 | }
150 | gestureDidEndedState = false
151 | case .ended, .failed, .cancelled:
152 | gestureDidEndedState = true
153 | default: break
154 | }
155 | }
156 | }
157 |
158 | // MARK: PanGesture Delegates
159 | extension ResizableControllerObserver {
160 |
161 | func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
162 |
163 | guard let currentView = panGesture.view, gestureRecognizer == panGesture else {
164 | return false
165 | }
166 |
167 | switch panGesture.dragDirection(inView: currentView) {
168 | case .upwards where !isHeightEqualToEstimatedHeight:
169 | guard delegate?.initialTopOffset != delegate?.finalTopOffset else { return false }
170 | return true
171 | case .downwards:
172 | return true
173 | case .idle where !isHeightEqualToEstimatedHeight:
174 | return true
175 | default: return false
176 | }
177 | }
178 |
179 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
180 | shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
181 | guard let currentView = gestureRecognizer.view,
182 | let otherView = otherGestureRecognizer.view else {
183 | return false
184 | }
185 |
186 | let isPanGesture = gestureRecognizer == panGesture
187 | let isDescendant = otherView.isDescendant(of: currentView)
188 |
189 | guard isPanGesture && isDescendant else {
190 | return false
191 | }
192 |
193 | guard let scrollView = otherView as? UIScrollView else {
194 | return true
195 | }
196 |
197 | return scrollView.contentOffset.y == 0
198 | }
199 | }
200 |
201 | // MARK: All About View Transaltion
202 |
203 | private extension ResizableControllerObserver {
204 |
205 | var isHeightEqualToEstimatedHeight: Bool {
206 | guard let view = view else { return false }
207 | return Int(view.frame.minY) == Int(estimatedFinalTopOffset)
208 | }
209 |
210 | /// performs resizable transformation for presented and presenting view controllers
211 | func translate(value: CGFloat) {
212 | delegate?.willMoveTopOffset(value: value)
213 | UIView.animate(withDuration: animationDuration, animations: {
214 | self.view?.frame.origin.y = value
215 | self.presentingViewTransaltion(transaltion: value)
216 | }, completion: { _ in
217 | self.delegate?.didMoveTopOffset(value: value)
218 | self.panGesture.setTranslation(.zero, in: self.view)
219 | })
220 | }
221 |
222 | func addSliderView() {
223 | guard let currentView = view, delegate?.shouldShowSlideUpIndication == true else { return }
224 |
225 | currentView.addSubview(slideIndicativeView)
226 |
227 | NSLayoutConstraint.activate([
228 | slideIndicativeView.centerXAnchor.constraint(equalTo: currentView.centerXAnchor),
229 | slideIndicativeView.topAnchor.constraint(equalTo: currentView.topAnchor, constant: 15)
230 | ])
231 |
232 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
233 | self.addSliderAnimation()
234 | }
235 | }
236 |
237 | /// Scales presenting view controller as per translation
238 | func presentingViewTransaltion(transaltion: CGFloat) {
239 | guard let viewController = presentingVC else { return }
240 | self.viewPosition.toggle(on: self.slideIndicativeView)
241 |
242 | switch viewController.viewPresentationStyle() {
243 |
244 | case .custom where estimatedFinalTopOffset == transaltion:
245 | presentingVCminY = viewController.view.frame.minY
246 | viewController.view.frame.origin.y = estimatedFinalTopOffset - 15
247 | case .custom where estimatedInitialTopOffset == transaltion:
248 | viewController.view.layer.transform = ViewControlerScale.backgroundPopUpScale.transform
249 | viewController.view.frame.origin.y = presentingVCminY
250 |
251 | case .default where estimatedFinalTopOffset == transaltion:
252 | presentingVCminY = viewController.view.frame.minY
253 | presentingVC?.view.frame.origin.y = .zero
254 | case .default where transaltion == estimatedInitialTopOffset:
255 | presentingVC?.view.frame.origin.y = presentingVCminY
256 |
257 | case .none where estimatedFinalTopOffset == transaltion:
258 | viewController.view.layer.transform = ViewControlerScale.backgroundFullScreenScale.transform
259 | case .none where estimatedInitialTopOffset == transaltion:
260 | viewController.view.layer.transform = ViewControlerScale.backgroundPopUpScale.transform
261 | default:
262 | viewController.view.layer.transform = ViewControlerScale.reset.transform
263 | }
264 | }
265 |
266 | /// adds slider bar animation
267 | func addSliderAnimation() {
268 | let group = CAAnimationGroup()
269 |
270 | let animation = CABasicAnimation(keyPath: "position")
271 | animation.fromValue = NSValue(cgPoint: CGPoint(x: self.slideIndicativeView.layer.position.x,
272 | y: self.slideIndicativeView.layer.position.y))
273 | animation.toValue = NSValue(cgPoint: CGPoint(x: self.slideIndicativeView.layer.position.x,
274 | y: self.slideIndicativeView.layer.position.y - 6))
275 |
276 | let animationForOpactity = CABasicAnimation(keyPath: "opacity")
277 | animationForOpactity.fromValue = 1
278 | animationForOpactity.toValue = 0.7
279 |
280 | group.animations = [animation, animationForOpactity]
281 | group.duration = 0.6
282 | group.autoreverses = true
283 | group.repeatCount = 2
284 | group.speed = 2
285 | group.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
286 |
287 | self.slideIndicativeView.layer.add(group, forKey: "position")
288 | }
289 | }
290 |
291 | // MARK: Pan helper functions to derive swipe direction
292 | extension UIPanGestureRecognizer {
293 | enum DraggingState {
294 | case upwards, downwards, idle
295 | }
296 |
297 | func dragDirection(inView view: UIView) -> DraggingState {
298 | let velocity = self.velocity(in: view)
299 | guard abs(velocity.x) < abs(velocity.y) else { return .idle }
300 | return velocity.y < 0 ? .upwards : .downwards
301 | }
302 | }
303 |
304 | enum SliderPosition {
305 | case present
306 | case dismiss
307 |
308 | mutating func toggle(on view: UIView) {
309 | switch self {
310 | case .present:
311 | view.alpha = 0
312 | self = .dismiss
313 | case .dismiss:
314 | view.alpha = 1
315 | self = .present
316 | }
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/ResizableController/ResizableTransitioningController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableTransitioningController.swift
3 | //
4 | // Created by Arjun Baru on 25/04/20.
5 | // Copyright © 2020 Paytm Money 🚀. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Manages present and dismiss for custom presented view controller
11 | class ResizableTransitioningController: NSObject, UIViewControllerTransitioningDelegate {
12 |
13 | private let animationDuration: TimeInterval
14 | private var gestureRecoganiser: ResizableControllerObserver!
15 | private var transitionincontroller: ResizableAnimatedController?
16 | private var shouldProceedWithTransitioning = true
17 |
18 | init(animationDuration: TimeInterval = ResizableConstants.animationDuration) {
19 | self.animationDuration = animationDuration
20 | }
21 |
22 | func animationController(forPresented presented: UIViewController,
23 | presenting: UIViewController,
24 | source: UIViewController)
25 | -> UIViewControllerAnimatedTransitioning? {
26 |
27 | guard let presentedChildVc = presented.children.first as? ResizableControllerPositionHandler else {
28 | shouldProceedWithTransitioning = false
29 | return nil
30 | }
31 |
32 | gestureRecoganiser = ResizableControllerObserver(in: presented.view, duration: animationDuration, delegate: presentedChildVc)
33 | gestureRecoganiser.presentingVC = presenting
34 | gestureRecoganiser.estimatedInitialTopOffset = presentedChildVc.initialTopOffset
35 |
36 | self.transitionincontroller = ResizableAnimatedController(
37 | initialTopOffset: presentedChildVc.initialTopOffset,
38 | animationDuration: animationDuration,
39 | isPresenting: true,
40 | estimatedFinalTopOffset: presentedChildVc.finalTopOffset)
41 |
42 | transitionincontroller?.isPresenting = true
43 | return transitionincontroller
44 | }
45 |
46 | func animationController(forDismissed dismissed: UIViewController)
47 | -> UIViewControllerAnimatedTransitioning? {
48 | guard shouldProceedWithTransitioning else { return nil }
49 | transitionincontroller?.isPresenting = false
50 | return transitionincontroller
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/ResizableController/UIView+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Extension.swift
3 | //
4 | // Created by Arjun Baru on 22/10/20.
5 | // Copyright © 2020 Paytm Money 🚀. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | /// Adds rounded corner to the view
12 | public func roundedCorners(withRadius radius: CGFloat) {
13 | layer.cornerRadius = radius
14 | }
15 |
16 | /// Helper function to layout constraint to edges
17 | /// - Parameter insets: Add inset to give padding from different edges
18 | public func edgesToSuperView(insets: UIEdgeInsets = .zero) {
19 |
20 | guard let superView = superview else { return }
21 | self.translatesAutoresizingMaskIntoConstraints = false
22 | NSLayoutConstraint.activate([
23 | self.topAnchor.constraint(equalTo: superView.topAnchor, constant: insets.top),
24 | self.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: insets.bottom),
25 | self.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: insets.left),
26 | self.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: insets.right)
27 | ])
28 | }
29 | }
30 |
31 | public struct ResizableConstants {
32 | public static let maximumTopOffset = UIScreen.main.bounds.height * 0.08
33 | public static let animationDuration: TimeInterval = 0.3
34 | }
35 |
36 |
37 | public extension UIViewController {
38 |
39 | /// An overload to implement Resizable Controller model presentation style.
40 | /// - Parameters:
41 | /// - viewControllerToPresent: ViewController which conforms to ResizableControllerPositionHandler protocol, Refer to ResizableControllerPositionHandler documentation for use case
42 | /// - animationDuration: Duration for animtion of view controller presenattion. Defaults to 0.3 seconds
43 | /// - completion: Optional parameter to provide additional functionllity after controller is presented.
44 | func present(_ viewControllerToPresent: ResizableControllerPositionHandler,
45 | animationDuration: TimeInterval = 0.3,
46 | completion: (() -> Void)? = nil) {
47 | let viewController = ResizableContainerViewController(animationDuration: animationDuration,
48 | childVC: viewControllerToPresent)
49 | self.present(viewController, animated: true, completion: completion)
50 | }
51 | }
52 |
53 |
54 | /// Helper ViewController to layout Resizable Controller Style.
55 | class ResizableContainerViewController: UIViewController {
56 | private var transitionAnimator: UIViewControllerTransitioningDelegate?
57 | init(animationDuration: TimeInterval,
58 | childVC: UIViewController) {
59 | self.transitionAnimator = ResizableTransitioningController(animationDuration: animationDuration)
60 | super.init(nibName: nil, bundle: nil)
61 |
62 | setup()
63 | addChildVC(childVC)
64 | }
65 |
66 | override var preferredStatusBarStyle: UIStatusBarStyle {
67 | return .lightContent
68 | }
69 |
70 | required init?(coder: NSCoder) {
71 | fatalError("init(coder:) has not been implemented")
72 | }
73 | private func setup() {
74 | modalPresentationStyle = .custom
75 | transitioningDelegate = transitionAnimator
76 | }
77 | private func addChildVC(_ child: UIViewController) {
78 | view.addSubview(child.view)
79 | addChild(child)
80 | child.didMove(toParent: self)
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/ResizableControllerSample/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Xcode
3 | .DS_Store
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 | xcuserdata/
20 |
21 | ResizableControllerSample.xcworkspace
22 | ## Workspace file
23 |
24 | ## Other
25 | *.moved-aside
26 | *.xccheckout
27 | *.xcuserstate
28 | *.xcscmblueprint
29 |
30 | ## Obj-C/Swift specific
31 | *.hmap
32 | *.ipa
33 | *.dSYM.zip
34 | *.dSYM
35 | *.app.dSYM.zip
--------------------------------------------------------------------------------
/ResizableControllerSample/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Paytm Money
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ResizableControllerSample/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'ResizableControllerSample' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for ResizableControllerSample
9 |
10 |
11 | pod 'ResizableController'
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/ResizableControllerSample/README.md:
--------------------------------------------------------------------------------
1 | # ResizableControllerSample
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 420CFFC62552B0A0005168E2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420CFFC52552B0A0005168E2 /* AppDelegate.swift */; };
11 | 420CFFC82552B0A0005168E2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420CFFC72552B0A0005168E2 /* SceneDelegate.swift */; };
12 | 420CFFCA2552B0A0005168E2 /* PresentingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420CFFC92552B0A0005168E2 /* PresentingViewController.swift */; };
13 | 420CFFCD2552B0A0005168E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 420CFFCB2552B0A0005168E2 /* Main.storyboard */; };
14 | 420CFFCF2552B0A2005168E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 420CFFCE2552B0A2005168E2 /* Assets.xcassets */; };
15 | 420CFFD22552B0A2005168E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 420CFFD02552B0A2005168E2 /* LaunchScreen.storyboard */; };
16 | 420CFFE02552B32D005168E2 /* FixedHeightPresentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420CFFDF2552B32D005168E2 /* FixedHeightPresentedViewController.swift */; };
17 | 420CFFFF2553BF73005168E2 /* ResizablePresentedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 420CFFFE2553BF73005168E2 /* ResizablePresentedViewController.swift */; };
18 | 42589E21255D752200F109F5 /* ResizableController in Frameworks */ = {isa = PBXBuildFile; productRef = 42589E20255D752200F109F5 /* ResizableController */; };
19 | 42EFAC8F255AAD82000CB6BC /* ResizableControllerSampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EFAC8E255AAD82000CB6BC /* ResizableControllerSampleUITests.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXContainerItemProxy section */
23 | 42EFAC91255AAD82000CB6BC /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = 420CFFBA2552B0A0005168E2 /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = 420CFFC12552B0A0005168E2;
28 | remoteInfo = ResizableControllerSample;
29 | };
30 | /* End PBXContainerItemProxy section */
31 |
32 | /* Begin PBXFileReference section */
33 | 420CFFC22552B0A0005168E2 /* ResizableControllerSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ResizableControllerSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 420CFFC52552B0A0005168E2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
35 | 420CFFC72552B0A0005168E2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
36 | 420CFFC92552B0A0005168E2 /* PresentingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentingViewController.swift; sourceTree = ""; };
37 | 420CFFCC2552B0A0005168E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
38 | 420CFFCE2552B0A2005168E2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
39 | 420CFFD12552B0A2005168E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
40 | 420CFFD32552B0A2005168E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | 420CFFDF2552B32D005168E2 /* FixedHeightPresentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FixedHeightPresentedViewController.swift; sourceTree = ""; };
42 | 420CFFFE2553BF73005168E2 /* ResizablePresentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizablePresentedViewController.swift; sourceTree = ""; };
43 | 42EFAC8C255AAD82000CB6BC /* ResizableControllerSampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResizableControllerSampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
44 | 42EFAC8E255AAD82000CB6BC /* ResizableControllerSampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizableControllerSampleUITests.swift; sourceTree = ""; };
45 | 42EFAC90255AAD82000CB6BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
46 | /* End PBXFileReference section */
47 |
48 | /* Begin PBXFrameworksBuildPhase section */
49 | 420CFFBF2552B0A0005168E2 /* Frameworks */ = {
50 | isa = PBXFrameworksBuildPhase;
51 | buildActionMask = 2147483647;
52 | files = (
53 | 42589E21255D752200F109F5 /* ResizableController in Frameworks */,
54 | );
55 | runOnlyForDeploymentPostprocessing = 0;
56 | };
57 | 42EFAC89255AAD82000CB6BC /* Frameworks */ = {
58 | isa = PBXFrameworksBuildPhase;
59 | buildActionMask = 2147483647;
60 | files = (
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | /* End PBXFrameworksBuildPhase section */
65 |
66 | /* Begin PBXGroup section */
67 | 420CFFB92552B0A0005168E2 = {
68 | isa = PBXGroup;
69 | children = (
70 | 420CFFC42552B0A0005168E2 /* ResizableControllerSample */,
71 | 42EFAC8D255AAD82000CB6BC /* ResizableControllerSampleUITests */,
72 | 420CFFC32552B0A0005168E2 /* Products */,
73 | AFE4132F4C4195658B17B2FA /* Pods */,
74 | );
75 | sourceTree = "";
76 | };
77 | 420CFFC32552B0A0005168E2 /* Products */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 420CFFC22552B0A0005168E2 /* ResizableControllerSample.app */,
81 | 42EFAC8C255AAD82000CB6BC /* ResizableControllerSampleUITests.xctest */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 420CFFC42552B0A0005168E2 /* ResizableControllerSample */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 420CFFC52552B0A0005168E2 /* AppDelegate.swift */,
90 | 420CFFC72552B0A0005168E2 /* SceneDelegate.swift */,
91 | 420CFFC92552B0A0005168E2 /* PresentingViewController.swift */,
92 | 420CFFDF2552B32D005168E2 /* FixedHeightPresentedViewController.swift */,
93 | 420CFFFE2553BF73005168E2 /* ResizablePresentedViewController.swift */,
94 | 420CFFCB2552B0A0005168E2 /* Main.storyboard */,
95 | 420CFFCE2552B0A2005168E2 /* Assets.xcassets */,
96 | 420CFFD02552B0A2005168E2 /* LaunchScreen.storyboard */,
97 | 420CFFD32552B0A2005168E2 /* Info.plist */,
98 | );
99 | path = ResizableControllerSample;
100 | sourceTree = "";
101 | };
102 | 42EFAC8D255AAD82000CB6BC /* ResizableControllerSampleUITests */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 42EFAC8E255AAD82000CB6BC /* ResizableControllerSampleUITests.swift */,
106 | 42EFAC90255AAD82000CB6BC /* Info.plist */,
107 | );
108 | path = ResizableControllerSampleUITests;
109 | sourceTree = "";
110 | };
111 | AFE4132F4C4195658B17B2FA /* Pods */ = {
112 | isa = PBXGroup;
113 | children = (
114 | );
115 | path = Pods;
116 | sourceTree = "";
117 | };
118 | /* End PBXGroup section */
119 |
120 | /* Begin PBXNativeTarget section */
121 | 420CFFC12552B0A0005168E2 /* ResizableControllerSample */ = {
122 | isa = PBXNativeTarget;
123 | buildConfigurationList = 420CFFD62552B0A2005168E2 /* Build configuration list for PBXNativeTarget "ResizableControllerSample" */;
124 | buildPhases = (
125 | 420CFFBE2552B0A0005168E2 /* Sources */,
126 | 420CFFBF2552B0A0005168E2 /* Frameworks */,
127 | 420CFFC02552B0A0005168E2 /* Resources */,
128 | );
129 | buildRules = (
130 | );
131 | dependencies = (
132 | );
133 | name = ResizableControllerSample;
134 | packageProductDependencies = (
135 | 42589E20255D752200F109F5 /* ResizableController */,
136 | );
137 | productName = ResizableControllerSample;
138 | productReference = 420CFFC22552B0A0005168E2 /* ResizableControllerSample.app */;
139 | productType = "com.apple.product-type.application";
140 | };
141 | 42EFAC8B255AAD82000CB6BC /* ResizableControllerSampleUITests */ = {
142 | isa = PBXNativeTarget;
143 | buildConfigurationList = 42EFAC95255AAD82000CB6BC /* Build configuration list for PBXNativeTarget "ResizableControllerSampleUITests" */;
144 | buildPhases = (
145 | 42EFAC88255AAD82000CB6BC /* Sources */,
146 | 42EFAC89255AAD82000CB6BC /* Frameworks */,
147 | 42EFAC8A255AAD82000CB6BC /* Resources */,
148 | );
149 | buildRules = (
150 | );
151 | dependencies = (
152 | 42EFAC92255AAD82000CB6BC /* PBXTargetDependency */,
153 | );
154 | name = ResizableControllerSampleUITests;
155 | productName = ResizableControllerSampleUITests;
156 | productReference = 42EFAC8C255AAD82000CB6BC /* ResizableControllerSampleUITests.xctest */;
157 | productType = "com.apple.product-type.bundle.ui-testing";
158 | };
159 | /* End PBXNativeTarget section */
160 |
161 | /* Begin PBXProject section */
162 | 420CFFBA2552B0A0005168E2 /* Project object */ = {
163 | isa = PBXProject;
164 | attributes = {
165 | LastSwiftUpdateCheck = 1200;
166 | LastUpgradeCheck = 1200;
167 | TargetAttributes = {
168 | 420CFFC12552B0A0005168E2 = {
169 | CreatedOnToolsVersion = 12.0.1;
170 | };
171 | 42EFAC8B255AAD82000CB6BC = {
172 | CreatedOnToolsVersion = 12.0.1;
173 | TestTargetID = 420CFFC12552B0A0005168E2;
174 | };
175 | };
176 | };
177 | buildConfigurationList = 420CFFBD2552B0A0005168E2 /* Build configuration list for PBXProject "ResizableControllerSample" */;
178 | compatibilityVersion = "Xcode 9.3";
179 | developmentRegion = en;
180 | hasScannedForEncodings = 0;
181 | knownRegions = (
182 | en,
183 | Base,
184 | );
185 | mainGroup = 420CFFB92552B0A0005168E2;
186 | packageReferences = (
187 | 42589E1F255D752200F109F5 /* XCRemoteSwiftPackageReference "ResizableController" */,
188 | );
189 | productRefGroup = 420CFFC32552B0A0005168E2 /* Products */;
190 | projectDirPath = "";
191 | projectRoot = "";
192 | targets = (
193 | 420CFFC12552B0A0005168E2 /* ResizableControllerSample */,
194 | 42EFAC8B255AAD82000CB6BC /* ResizableControllerSampleUITests */,
195 | );
196 | };
197 | /* End PBXProject section */
198 |
199 | /* Begin PBXResourcesBuildPhase section */
200 | 420CFFC02552B0A0005168E2 /* Resources */ = {
201 | isa = PBXResourcesBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 420CFFD22552B0A2005168E2 /* LaunchScreen.storyboard in Resources */,
205 | 420CFFCF2552B0A2005168E2 /* Assets.xcassets in Resources */,
206 | 420CFFCD2552B0A0005168E2 /* Main.storyboard in Resources */,
207 | );
208 | runOnlyForDeploymentPostprocessing = 0;
209 | };
210 | 42EFAC8A255AAD82000CB6BC /* Resources */ = {
211 | isa = PBXResourcesBuildPhase;
212 | buildActionMask = 2147483647;
213 | files = (
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | /* End PBXResourcesBuildPhase section */
218 |
219 | /* Begin PBXSourcesBuildPhase section */
220 | 420CFFBE2552B0A0005168E2 /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | 420CFFCA2552B0A0005168E2 /* PresentingViewController.swift in Sources */,
225 | 420CFFFF2553BF73005168E2 /* ResizablePresentedViewController.swift in Sources */,
226 | 420CFFE02552B32D005168E2 /* FixedHeightPresentedViewController.swift in Sources */,
227 | 420CFFC62552B0A0005168E2 /* AppDelegate.swift in Sources */,
228 | 420CFFC82552B0A0005168E2 /* SceneDelegate.swift in Sources */,
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | 42EFAC88255AAD82000CB6BC /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 42EFAC8F255AAD82000CB6BC /* ResizableControllerSampleUITests.swift in Sources */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | /* End PBXSourcesBuildPhase section */
241 |
242 | /* Begin PBXTargetDependency section */
243 | 42EFAC92255AAD82000CB6BC /* PBXTargetDependency */ = {
244 | isa = PBXTargetDependency;
245 | target = 420CFFC12552B0A0005168E2 /* ResizableControllerSample */;
246 | targetProxy = 42EFAC91255AAD82000CB6BC /* PBXContainerItemProxy */;
247 | };
248 | /* End PBXTargetDependency section */
249 |
250 | /* Begin PBXVariantGroup section */
251 | 420CFFCB2552B0A0005168E2 /* Main.storyboard */ = {
252 | isa = PBXVariantGroup;
253 | children = (
254 | 420CFFCC2552B0A0005168E2 /* Base */,
255 | );
256 | name = Main.storyboard;
257 | sourceTree = "";
258 | };
259 | 420CFFD02552B0A2005168E2 /* LaunchScreen.storyboard */ = {
260 | isa = PBXVariantGroup;
261 | children = (
262 | 420CFFD12552B0A2005168E2 /* Base */,
263 | );
264 | name = LaunchScreen.storyboard;
265 | sourceTree = "";
266 | };
267 | /* End PBXVariantGroup section */
268 |
269 | /* Begin XCBuildConfiguration section */
270 | 420CFFD42552B0A2005168E2 /* Debug */ = {
271 | isa = XCBuildConfiguration;
272 | buildSettings = {
273 | ALWAYS_SEARCH_USER_PATHS = NO;
274 | CLANG_ANALYZER_NONNULL = YES;
275 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
277 | CLANG_CXX_LIBRARY = "libc++";
278 | CLANG_ENABLE_MODULES = YES;
279 | CLANG_ENABLE_OBJC_ARC = YES;
280 | CLANG_ENABLE_OBJC_WEAK = YES;
281 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
282 | CLANG_WARN_BOOL_CONVERSION = YES;
283 | CLANG_WARN_COMMA = YES;
284 | CLANG_WARN_CONSTANT_CONVERSION = YES;
285 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
287 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
288 | CLANG_WARN_EMPTY_BODY = YES;
289 | CLANG_WARN_ENUM_CONVERSION = YES;
290 | CLANG_WARN_INFINITE_RECURSION = YES;
291 | CLANG_WARN_INT_CONVERSION = YES;
292 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
293 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
294 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
295 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
296 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
297 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
298 | CLANG_WARN_STRICT_PROTOTYPES = YES;
299 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
300 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
301 | CLANG_WARN_UNREACHABLE_CODE = YES;
302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
303 | COPY_PHASE_STRIP = NO;
304 | DEBUG_INFORMATION_FORMAT = dwarf;
305 | ENABLE_STRICT_OBJC_MSGSEND = YES;
306 | ENABLE_TESTABILITY = YES;
307 | GCC_C_LANGUAGE_STANDARD = gnu11;
308 | GCC_DYNAMIC_NO_PIC = NO;
309 | GCC_NO_COMMON_BLOCKS = YES;
310 | GCC_OPTIMIZATION_LEVEL = 0;
311 | GCC_PREPROCESSOR_DEFINITIONS = (
312 | "DEBUG=1",
313 | "$(inherited)",
314 | );
315 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
316 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
317 | GCC_WARN_UNDECLARED_SELECTOR = YES;
318 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
319 | GCC_WARN_UNUSED_FUNCTION = YES;
320 | GCC_WARN_UNUSED_VARIABLE = YES;
321 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
322 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
323 | MTL_FAST_MATH = YES;
324 | ONLY_ACTIVE_ARCH = YES;
325 | SDKROOT = iphoneos;
326 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
327 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
328 | };
329 | name = Debug;
330 | };
331 | 420CFFD52552B0A2005168E2 /* Release */ = {
332 | isa = XCBuildConfiguration;
333 | buildSettings = {
334 | ALWAYS_SEARCH_USER_PATHS = NO;
335 | CLANG_ANALYZER_NONNULL = YES;
336 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
338 | CLANG_CXX_LIBRARY = "libc++";
339 | CLANG_ENABLE_MODULES = YES;
340 | CLANG_ENABLE_OBJC_ARC = YES;
341 | CLANG_ENABLE_OBJC_WEAK = YES;
342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
343 | CLANG_WARN_BOOL_CONVERSION = YES;
344 | CLANG_WARN_COMMA = YES;
345 | CLANG_WARN_CONSTANT_CONVERSION = YES;
346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
348 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
349 | CLANG_WARN_EMPTY_BODY = YES;
350 | CLANG_WARN_ENUM_CONVERSION = YES;
351 | CLANG_WARN_INFINITE_RECURSION = YES;
352 | CLANG_WARN_INT_CONVERSION = YES;
353 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
354 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
355 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
356 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
357 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
359 | CLANG_WARN_STRICT_PROTOTYPES = YES;
360 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
361 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
362 | CLANG_WARN_UNREACHABLE_CODE = YES;
363 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
364 | COPY_PHASE_STRIP = NO;
365 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
366 | ENABLE_NS_ASSERTIONS = NO;
367 | ENABLE_STRICT_OBJC_MSGSEND = YES;
368 | GCC_C_LANGUAGE_STANDARD = gnu11;
369 | GCC_NO_COMMON_BLOCKS = YES;
370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
372 | GCC_WARN_UNDECLARED_SELECTOR = YES;
373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
374 | GCC_WARN_UNUSED_FUNCTION = YES;
375 | GCC_WARN_UNUSED_VARIABLE = YES;
376 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
377 | MTL_ENABLE_DEBUG_INFO = NO;
378 | MTL_FAST_MATH = YES;
379 | SDKROOT = iphoneos;
380 | SWIFT_COMPILATION_MODE = wholemodule;
381 | SWIFT_OPTIMIZATION_LEVEL = "-O";
382 | VALIDATE_PRODUCT = YES;
383 | };
384 | name = Release;
385 | };
386 | 420CFFD72552B0A2005168E2 /* Debug */ = {
387 | isa = XCBuildConfiguration;
388 | buildSettings = {
389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
390 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
391 | CODE_SIGN_STYLE = Automatic;
392 | DEVELOPMENT_TEAM = 885LR8YVNT;
393 | INFOPLIST_FILE = ResizableControllerSample/Info.plist;
394 | LD_RUNPATH_SEARCH_PATHS = (
395 | "$(inherited)",
396 | "@executable_path/Frameworks",
397 | );
398 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerSample;
399 | PRODUCT_NAME = "$(TARGET_NAME)";
400 | SWIFT_VERSION = 5.0;
401 | TARGETED_DEVICE_FAMILY = "1,2";
402 | };
403 | name = Debug;
404 | };
405 | 420CFFD82552B0A2005168E2 /* Release */ = {
406 | isa = XCBuildConfiguration;
407 | buildSettings = {
408 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
409 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
410 | CODE_SIGN_STYLE = Automatic;
411 | DEVELOPMENT_TEAM = 885LR8YVNT;
412 | INFOPLIST_FILE = ResizableControllerSample/Info.plist;
413 | LD_RUNPATH_SEARCH_PATHS = (
414 | "$(inherited)",
415 | "@executable_path/Frameworks",
416 | );
417 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerSample;
418 | PRODUCT_NAME = "$(TARGET_NAME)";
419 | SWIFT_VERSION = 5.0;
420 | TARGETED_DEVICE_FAMILY = "1,2";
421 | };
422 | name = Release;
423 | };
424 | 42EFAC93255AAD82000CB6BC /* Debug */ = {
425 | isa = XCBuildConfiguration;
426 | buildSettings = {
427 | CODE_SIGN_STYLE = Automatic;
428 | DEVELOPMENT_TEAM = V83QP83683;
429 | INFOPLIST_FILE = ResizableControllerSampleUITests/Info.plist;
430 | LD_RUNPATH_SEARCH_PATHS = (
431 | "$(inherited)",
432 | "@executable_path/Frameworks",
433 | "@loader_path/Frameworks",
434 | );
435 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerSampleUITests;
436 | PRODUCT_NAME = "$(TARGET_NAME)";
437 | SWIFT_VERSION = 5.0;
438 | TARGETED_DEVICE_FAMILY = "1,2";
439 | TEST_TARGET_NAME = ResizableControllerSample;
440 | };
441 | name = Debug;
442 | };
443 | 42EFAC94255AAD82000CB6BC /* Release */ = {
444 | isa = XCBuildConfiguration;
445 | buildSettings = {
446 | CODE_SIGN_STYLE = Automatic;
447 | DEVELOPMENT_TEAM = V83QP83683;
448 | INFOPLIST_FILE = ResizableControllerSampleUITests/Info.plist;
449 | LD_RUNPATH_SEARCH_PATHS = (
450 | "$(inherited)",
451 | "@executable_path/Frameworks",
452 | "@loader_path/Frameworks",
453 | );
454 | PRODUCT_BUNDLE_IDENTIFIER = com.paytmmoney.opensource.ResizableControllerSampleUITests;
455 | PRODUCT_NAME = "$(TARGET_NAME)";
456 | SWIFT_VERSION = 5.0;
457 | TARGETED_DEVICE_FAMILY = "1,2";
458 | TEST_TARGET_NAME = ResizableControllerSample;
459 | };
460 | name = Release;
461 | };
462 | /* End XCBuildConfiguration section */
463 |
464 | /* Begin XCConfigurationList section */
465 | 420CFFBD2552B0A0005168E2 /* Build configuration list for PBXProject "ResizableControllerSample" */ = {
466 | isa = XCConfigurationList;
467 | buildConfigurations = (
468 | 420CFFD42552B0A2005168E2 /* Debug */,
469 | 420CFFD52552B0A2005168E2 /* Release */,
470 | );
471 | defaultConfigurationIsVisible = 0;
472 | defaultConfigurationName = Release;
473 | };
474 | 420CFFD62552B0A2005168E2 /* Build configuration list for PBXNativeTarget "ResizableControllerSample" */ = {
475 | isa = XCConfigurationList;
476 | buildConfigurations = (
477 | 420CFFD72552B0A2005168E2 /* Debug */,
478 | 420CFFD82552B0A2005168E2 /* Release */,
479 | );
480 | defaultConfigurationIsVisible = 0;
481 | defaultConfigurationName = Release;
482 | };
483 | 42EFAC95255AAD82000CB6BC /* Build configuration list for PBXNativeTarget "ResizableControllerSampleUITests" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | 42EFAC93255AAD82000CB6BC /* Debug */,
487 | 42EFAC94255AAD82000CB6BC /* Release */,
488 | );
489 | defaultConfigurationIsVisible = 0;
490 | defaultConfigurationName = Release;
491 | };
492 | /* End XCConfigurationList section */
493 |
494 | /* Begin XCRemoteSwiftPackageReference section */
495 | 42589E1F255D752200F109F5 /* XCRemoteSwiftPackageReference "ResizableController" */ = {
496 | isa = XCRemoteSwiftPackageReference;
497 | repositoryURL = "https://github.com/paytmmoney/ResizableController";
498 | requirement = {
499 | branch = dev/SwiftPackageManager;
500 | kind = branch;
501 | };
502 | };
503 | /* End XCRemoteSwiftPackageReference section */
504 |
505 | /* Begin XCSwiftPackageProductDependency section */
506 | 42589E20255D752200F109F5 /* ResizableController */ = {
507 | isa = XCSwiftPackageProductDependency;
508 | package = 42589E1F255D752200F109F5 /* XCRemoteSwiftPackageReference "ResizableController" */;
509 | productName = ResizableController;
510 | };
511 | /* End XCSwiftPackageProductDependency section */
512 | };
513 | rootObject = 420CFFBA2552B0A0005168E2 /* Project object */;
514 | }
515 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ResizableControllerSample
4 | //
5 | // Created by Arjun Baru on 04/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
122 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/FixedHeightPresentedViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FixedHeightPresentedViewController.swift
3 | // ResizableControllerSample
4 | //
5 | // Created by Arjun Baru on 04/11/20.
6 | //
7 |
8 | import UIKit
9 | import ResizableController
10 |
11 | class FixedHeightPresentedViewController: UIViewController {
12 |
13 | @IBOutlet weak var swipeLabel: UILabel!
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | }
17 | }
18 |
19 | extension FixedHeightPresentedViewController: ResizableControllerPositionHandler {}
20 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/PresentingViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PresentingViewController.swift
3 | // ResizableControllerSample
4 | //
5 | // Created by Arjun Baru on 04/11/20.
6 | //
7 |
8 | import UIKit
9 | import ResizableController
10 |
11 | class PresentingViewController: UIViewController {
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 | title = "Resizable Controller"
15 | }
16 |
17 | @IBAction func onTapOfCustomHeightController(_ sender: Any) {
18 |
19 | let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ResizablePresentedViewController") as ResizablePresentedViewController
20 | self.present(viewController)
21 | }
22 |
23 | @IBAction func onTapOfFixedHeightController(_ sender: Any) {
24 | let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "FixedPresentingViewController") as FixedHeightPresentedViewController
25 | self.present(viewController)
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/ResizablePresentedViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizablePresentedViewController.swift
3 | // ResizableControllerSample
4 | //
5 | // Created by Arjun Baru on 05/11/20.
6 | //
7 |
8 | import UIKit
9 | import ResizableController
10 |
11 | class ResizablePresentedViewController: UIViewController {
12 |
13 | @IBOutlet weak var swipeLabel: UILabel!
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | }
17 | }
18 |
19 | extension ResizablePresentedViewController: ResizableControllerPositionHandler {
20 | var initialTopOffset: CGFloat {
21 | 500
22 | }
23 |
24 | func didMoveTopOffset(value: CGFloat) {
25 | if value == initialTopOffset {
26 | self.swipeLabel.text = "Swipe up to full size"
27 | }
28 |
29 | if value == finalTopOffset {
30 | self.swipeLabel.text = "Swipe down to half screen"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // ResizableControllerSample
4 | //
5 | // Created by Arjun Baru on 04/11/20.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSampleUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ResizableControllerSample/ResizableControllerSampleUITests/ResizableControllerSampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableControllerSampleUITests.swift
3 | // ResizableControllerSampleUITests
4 | //
5 | // Created by Arjun Baru on 10/11/20.
6 | //
7 |
8 | import XCTest
9 |
10 | class ResizableControllerSampleUITests: XCTestCase {
11 |
12 | func testResizableController() throws {
13 | let app = XCUIApplication()
14 | app.launch()
15 |
16 |
17 | app.buttons["Show Custom Height Controller"].staticTexts["Show Custom Height Controller"].tap()
18 |
19 | let element2 = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element(boundBy: 1)
20 |
21 | // Swipe to full screen
22 | element2.swipeUp()
23 | sleep(1)
24 |
25 | // swipe to half screen
26 | element2.swipeDown()
27 | sleep(1)
28 |
29 | // back tap to dismiss
30 | app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element(boundBy: 1).tap()
31 | }
32 |
33 | func testFixedHeightController() throws {
34 | let app = XCUIApplication()
35 | app.launch()
36 |
37 | app.buttons["Show Fixed Height Controller"].staticTexts["Show Fixed Height Controller"].tap()
38 | let element2 = app.children(matching: .window).element(boundBy: 0).children(matching: .other).element.children(matching: .other).element(boundBy: 1)
39 |
40 | // test swipe up on full screen
41 | element2.swipeUp()
42 | sleep(1)
43 |
44 | // swipe down to dismiss
45 | element2.swipeDown()
46 | sleep(1)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ResizableControllerUnitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ResizableControllerUnitTests/ResizableControllerUnitTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResizableControllerUnitTests.swift
3 | // ResizableControllerUnitTests
4 | //
5 | // Created by Arjun Baru on 10/11/20.
6 | //
7 |
8 | import XCTest
9 | import UIKit
10 | @testable import ResizableController
11 |
12 | class ResizableControllerUnitTests: XCTestCase {
13 |
14 | var presentedResizableVC : ResizableControllerPositionHandler = ResizableControllerPositionHandlerMock()
15 | var presentedFixedSizeVC : ResizableControllerPositionHandler = FixedSizeControllerPositionHandlerMock()
16 | var panHandler: ResizableControllerObserver?
17 |
18 | func testResizableControllerPositionHandlerDelegate() throws {
19 | panHandler = ResizableControllerObserver(in: presentedResizableVC.onView, duration: 0.3, delegate: presentedResizableVC)
20 | // test for custom initial top offset updated on client end
21 | XCTAssertEqual(presentedResizableVC.initialTopOffset, panHandler?.estimatedInitialTopOffset)
22 |
23 | // test for maximum top offset updated on client end
24 | XCTAssertEqual(presentedResizableVC.finalTopOffset, panHandler?.estimatedFinalTopOffset)
25 |
26 | // test for updated sliderbar colour on client end
27 | XCTAssertEqual(presentedResizableVC.sliderBackgroundColor, panHandler?.delegate?.sliderBackgroundColor)
28 | }
29 |
30 | func testFixedSizeControllerPositionHandlerDelegate() throws {
31 | panHandler = ResizableControllerObserver(in: presentedResizableVC.onView, duration: 0.3, delegate: presentedFixedSizeVC)
32 | // test for custom initial top offset for default implementation
33 | XCTAssertEqual(presentedFixedSizeVC.initialTopOffset, panHandler?.estimatedInitialTopOffset)
34 |
35 | // test for maximum top offset for default implementation
36 | XCTAssertEqual(presentedFixedSizeVC.finalTopOffset, panHandler?.estimatedFinalTopOffset)
37 |
38 | // test for updated sliderbar for default colour
39 | XCTAssertEqual(presentedFixedSizeVC.sliderBackgroundColor, panHandler?.delegate?.sliderBackgroundColor)
40 | }
41 |
42 | }
43 |
44 | /// Resizable controller with custom implementation
45 | class ResizableControllerPositionHandlerMock: UIViewController, ResizableControllerPositionHandler {
46 | var initialTopOffset: CGFloat {
47 | 500
48 | }
49 |
50 | var finalTopOffset: CGFloat {
51 | 200
52 | }
53 |
54 | var sliderBackgroundColor: UIColor {
55 | UIColor.red.withAlphaComponent(0.5)
56 | }
57 | }
58 |
59 | /// Resizable controller with Default implementation
60 | class FixedSizeControllerPositionHandlerMock: UIViewController, ResizableControllerPositionHandler {
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/ResizableController/ResizableAnimatedController.swift:
--------------------------------------------------------------------------------
1 | ../../ResizableController/ResizableAnimatedController.swift
--------------------------------------------------------------------------------
/Sources/ResizableController/ResizableControllerObserver.swift:
--------------------------------------------------------------------------------
1 | ../../ResizableController/ResizableControllerObserver.swift
--------------------------------------------------------------------------------
/Sources/ResizableController/ResizableTransitioningController.swift:
--------------------------------------------------------------------------------
1 | ../../ResizableController/ResizableTransitioningController.swift
--------------------------------------------------------------------------------
/Sources/ResizableController/UIView+Extension.swift:
--------------------------------------------------------------------------------
1 | ../../ResizableController/UIView+Extension.swift
--------------------------------------------------------------------------------