├── .gitignore
├── Example
├── ContentViewController.storyboard
├── ContentViewController.swift
├── DummyScreenGenerator.swift
├── ScreenSelectorExample.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── ScreenSelectorExample.xcscheme
├── ScreenSelectorExample.xcworkspace
│ └── contents.xcworkspacedata
├── ScreenSelectorExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── ExtendedViewController.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── ExtendedViewController.swift
│ ├── Info.plist
│ ├── ViewController.storyboard
│ ├── ViewController.swift
│ └── example_bg@2x.jpg
├── ScreenSelectorExampleTests
│ ├── Info.plist
│ └── ScreenSelectorExampleTests.swift
└── ScreenSelectorExampleUITests
│ ├── Info.plist
│ └── ScreenSelectorExampleUITests.swift
├── LICENSE
├── README.md
├── ScreenSelector.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── ScreenSelector.xcscheme
├── ScreenSelector
├── DummyScreenGenerator.swift
├── Info.plist
├── ReversibleAnimatedTransitioning.swift
├── ScreenPreviewView.swift
├── ScreenSelector.h
├── ScreenSelectorPreviewable.swift
├── ScreenSelectorTransitioningAnimator.swift
├── ScreenSelectorView.swift
├── ScreenSelectorViewController.swift
└── SpecularReflectionLayer.swift
├── ScreenSelectorTests
├── Info.plist
└── ScreenSelectorTests.swift
└── preview.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/xcode,swift,objective-c,carthage
2 |
3 | ### OSX ###
4 | *.DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 |
12 | # Thumbnails
13 | ._*
14 |
15 | # Files that might appear in the root of a volume
16 | .DocumentRevisions-V100
17 | .fseventsd
18 | .Spotlight-V100
19 | .TemporaryItems
20 | .Trashes
21 | .VolumeIcon.icns
22 | .com.apple.timemachine.donotpresent
23 |
24 | # Directories potentially created on remote AFP share
25 | .AppleDB
26 | .AppleDesktop
27 | Network Trash Folder
28 | Temporary Items
29 | .apdisk
30 |
31 | ### Xcode ###
32 | # Xcode
33 | #
34 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
35 |
36 | ## Playgrounds
37 | timeline.xctimeline
38 | playground.xcworkspace
39 |
40 | # Carthage
41 | #
42 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
43 | #Carthage/Checkouts
44 |
45 | Carthage/Build
46 |
47 | ### Objective-C ###
48 | # Xcode
49 | #
50 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
51 |
52 | ## Build generated
53 | build/
54 | DerivedData
55 |
56 | ## Various settings
57 | *.pbxuser
58 | !default.pbxuser
59 | *.mode1v3
60 | !default.mode1v3
61 | *.mode2v3
62 | !default.mode2v3
63 | *.perspectivev3
64 | !default.perspectivev3
65 | xcuserdata
66 |
67 | ## Other
68 | *.xccheckout
69 | *.moved-aside
70 | *.xcuserstate
71 | *.xcscmblueprint
72 |
73 | ## Obj-C/Swift specific
74 | *.hmap
75 | *.ipa
76 |
77 | ### Objective-C Patch ###
78 | *.xcscmblueprint
79 |
80 |
81 | ### Carthage ###
82 | # Carthage - A simple, decentralized dependency manager for Cocoa
83 | Carthage.checkout
84 | Carthage.build
--------------------------------------------------------------------------------
/Example/ContentViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
--------------------------------------------------------------------------------
/Example/ContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentViewController.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/22.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ScreenSelector
11 |
12 | final class ContentViewController: UIViewController, ScreenSelectorPreviewable {
13 |
14 | @IBOutlet weak var textLabel: UILabel!
15 | @IBOutlet weak var backgroundImageView: UIImageView?
16 |
17 | var thumbnailImage: UIImage? {
18 | get {
19 | return UIImage(named: "example_bg.jpg")
20 | }
21 | }
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | let tapRecog = UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
26 | view.addGestureRecognizer(tapRecog)
27 | }
28 |
29 | func tapped(tapRecog: UITapGestureRecognizer) {
30 | dismissViewControllerAnimated(true, completion: nil)
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Example/DummyScreenGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DummyScreenGenerator.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/26.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ScreenSelector
11 |
12 | final class DummyScreenGenerator {
13 |
14 | class func generateViewControllers() -> [ScreenSelectorPreviewable] {
15 | var viewControllers = [ScreenSelectorPreviewable]()
16 | for i in 0.stride(to: 5, by: 1) {
17 | let vc = UIStoryboard.init(name: "ContentViewController", bundle: nil).instantiateInitialViewController() as? ContentViewController
18 | vc?.view.tag = i
19 | vc?.textLabel.text = "\(i)"
20 | vc?.title = "Title \(i)"
21 | if let v = vc as? ScreenSelectorPreviewable {
22 | viewControllers.append(v)
23 | }
24 | }
25 | return viewControllers
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2D38501E1D61898500DA1F6A /* ScreenSelector.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 2D3850181D6188C000DA1F6A /* ScreenSelector.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
11 | 2D38501F1D6189A300DA1F6A /* ScreenSelector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D3850181D6188C000DA1F6A /* ScreenSelector.framework */; };
12 | 2D3850291D61909800DA1F6A /* ContentViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2D3850261D61909800DA1F6A /* ContentViewController.storyboard */; };
13 | 2D38502A1D61909800DA1F6A /* ContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3850271D61909800DA1F6A /* ContentViewController.swift */; };
14 | 2D38502B1D61909800DA1F6A /* DummyScreenGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3850281D61909800DA1F6A /* DummyScreenGenerator.swift */; };
15 | 2D38502D1D61BE5600DA1F6A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38502C1D61BE5600DA1F6A /* ViewController.swift */; };
16 | 2D38502F1D61BE6100DA1F6A /* ViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2D38502E1D61BE6100DA1F6A /* ViewController.storyboard */; };
17 | 752025501D3F9AA5000096E1 /* example_bg@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7520254F1D3F9AA5000096E1 /* example_bg@2x.jpg */; };
18 | 75E4E17E1D3F68A5001496FC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E4E17D1D3F68A5001496FC /* AppDelegate.swift */; };
19 | 75E4E1801D3F68A5001496FC /* ExtendedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E4E17F1D3F68A5001496FC /* ExtendedViewController.swift */; };
20 | 75E4E1831D3F68A5001496FC /* ExtendedViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 75E4E1811D3F68A5001496FC /* ExtendedViewController.storyboard */; };
21 | 75E4E1851D3F68A5001496FC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 75E4E1841D3F68A5001496FC /* Assets.xcassets */; };
22 | 75E4E1881D3F68A5001496FC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 75E4E1861D3F68A5001496FC /* LaunchScreen.storyboard */; };
23 | 75E4E1931D3F68A5001496FC /* ScreenSelectorExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E4E1921D3F68A5001496FC /* ScreenSelectorExampleTests.swift */; };
24 | 75E4E19E1D3F68A5001496FC /* ScreenSelectorExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75E4E19D1D3F68A5001496FC /* ScreenSelectorExampleUITests.swift */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXContainerItemProxy section */
28 | 2D3850171D6188C000DA1F6A /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */;
31 | proxyType = 2;
32 | remoteGlobalIDString = 2D384F8E1D6177E200DA1F6A;
33 | remoteInfo = ScreenSelector;
34 | };
35 | 2D3850191D6188C000DA1F6A /* PBXContainerItemProxy */ = {
36 | isa = PBXContainerItemProxy;
37 | containerPortal = 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */;
38 | proxyType = 2;
39 | remoteGlobalIDString = 2D384F981D6177E200DA1F6A;
40 | remoteInfo = ScreenSelectorTests;
41 | };
42 | 2D38501B1D6188DC00DA1F6A /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */;
45 | proxyType = 1;
46 | remoteGlobalIDString = 2D384F8D1D6177E200DA1F6A;
47 | remoteInfo = ScreenSelector;
48 | };
49 | 75E4E18F1D3F68A5001496FC /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = 75E4E1721D3F68A5001496FC /* Project object */;
52 | proxyType = 1;
53 | remoteGlobalIDString = 75E4E1791D3F68A5001496FC;
54 | remoteInfo = ScreenSelectorExample;
55 | };
56 | 75E4E19A1D3F68A5001496FC /* PBXContainerItemProxy */ = {
57 | isa = PBXContainerItemProxy;
58 | containerPortal = 75E4E1721D3F68A5001496FC /* Project object */;
59 | proxyType = 1;
60 | remoteGlobalIDString = 75E4E1791D3F68A5001496FC;
61 | remoteInfo = ScreenSelectorExample;
62 | };
63 | /* End PBXContainerItemProxy section */
64 |
65 | /* Begin PBXCopyFilesBuildPhase section */
66 | 2D38501D1D61897800DA1F6A /* Copy Frameworks */ = {
67 | isa = PBXCopyFilesBuildPhase;
68 | buildActionMask = 2147483647;
69 | dstPath = "";
70 | dstSubfolderSpec = 7;
71 | files = (
72 | 2D38501E1D61898500DA1F6A /* ScreenSelector.framework in Copy Frameworks */,
73 | );
74 | name = "Copy Frameworks";
75 | runOnlyForDeploymentPostprocessing = 0;
76 | };
77 | 7539D2CF1D463C8C003EAB79 /* Embed Frameworks */ = {
78 | isa = PBXCopyFilesBuildPhase;
79 | buildActionMask = 2147483647;
80 | dstPath = "";
81 | dstSubfolderSpec = 10;
82 | files = (
83 | );
84 | name = "Embed Frameworks";
85 | runOnlyForDeploymentPostprocessing = 0;
86 | };
87 | /* End PBXCopyFilesBuildPhase section */
88 |
89 | /* Begin PBXFileReference section */
90 | 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ScreenSelector.xcodeproj; path = ../ScreenSelector.xcodeproj; sourceTree = ""; };
91 | 2D3850261D61909800DA1F6A /* ContentViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = ContentViewController.storyboard; path = ../ContentViewController.storyboard; sourceTree = ""; };
92 | 2D3850271D61909800DA1F6A /* ContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContentViewController.swift; path = ../ContentViewController.swift; sourceTree = ""; };
93 | 2D3850281D61909800DA1F6A /* DummyScreenGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DummyScreenGenerator.swift; path = ../DummyScreenGenerator.swift; sourceTree = ""; };
94 | 2D38502C1D61BE5600DA1F6A /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
95 | 2D38502E1D61BE6100DA1F6A /* ViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ViewController.storyboard; sourceTree = ""; };
96 | 7520254F1D3F9AA5000096E1 /* example_bg@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "example_bg@2x.jpg"; sourceTree = ""; };
97 | 75E4E17A1D3F68A5001496FC /* ScreenSelectorExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ScreenSelectorExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
98 | 75E4E17D1D3F68A5001496FC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
99 | 75E4E17F1D3F68A5001496FC /* ExtendedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedViewController.swift; sourceTree = ""; };
100 | 75E4E1821D3F68A5001496FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/ExtendedViewController.storyboard; sourceTree = ""; };
101 | 75E4E1841D3F68A5001496FC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
102 | 75E4E1871D3F68A5001496FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
103 | 75E4E1891D3F68A5001496FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
104 | 75E4E18E1D3F68A5001496FC /* ScreenSelectorExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreenSelectorExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
105 | 75E4E1921D3F68A5001496FC /* ScreenSelectorExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSelectorExampleTests.swift; sourceTree = ""; };
106 | 75E4E1941D3F68A5001496FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
107 | 75E4E1991D3F68A5001496FC /* ScreenSelectorExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreenSelectorExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
108 | 75E4E19D1D3F68A5001496FC /* ScreenSelectorExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSelectorExampleUITests.swift; sourceTree = ""; };
109 | 75E4E19F1D3F68A5001496FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
110 | /* End PBXFileReference section */
111 |
112 | /* Begin PBXFrameworksBuildPhase section */
113 | 75E4E1771D3F68A5001496FC /* Frameworks */ = {
114 | isa = PBXFrameworksBuildPhase;
115 | buildActionMask = 2147483647;
116 | files = (
117 | 2D38501F1D6189A300DA1F6A /* ScreenSelector.framework in Frameworks */,
118 | );
119 | runOnlyForDeploymentPostprocessing = 0;
120 | };
121 | 75E4E18B1D3F68A5001496FC /* Frameworks */ = {
122 | isa = PBXFrameworksBuildPhase;
123 | buildActionMask = 2147483647;
124 | files = (
125 | );
126 | runOnlyForDeploymentPostprocessing = 0;
127 | };
128 | 75E4E1961D3F68A5001496FC /* Frameworks */ = {
129 | isa = PBXFrameworksBuildPhase;
130 | buildActionMask = 2147483647;
131 | files = (
132 | );
133 | runOnlyForDeploymentPostprocessing = 0;
134 | };
135 | /* End PBXFrameworksBuildPhase section */
136 |
137 | /* Begin PBXGroup section */
138 | 2D384FA81D6179C400DA1F6A /* ScreenSelectorViewController Example */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 75E4E17F1D3F68A5001496FC /* ExtendedViewController.swift */,
142 | 75E4E1811D3F68A5001496FC /* ExtendedViewController.storyboard */,
143 | );
144 | name = "ScreenSelectorViewController Example";
145 | sourceTree = "";
146 | };
147 | 2D384FA91D6179D800DA1F6A /* ScreenSelectorView Example */ = {
148 | isa = PBXGroup;
149 | children = (
150 | 2D38502C1D61BE5600DA1F6A /* ViewController.swift */,
151 | 2D38502E1D61BE6100DA1F6A /* ViewController.storyboard */,
152 | );
153 | name = "ScreenSelectorView Example";
154 | sourceTree = "";
155 | };
156 | 2D3850131D6188C000DA1F6A /* Products */ = {
157 | isa = PBXGroup;
158 | children = (
159 | 2D3850181D6188C000DA1F6A /* ScreenSelector.framework */,
160 | 2D38501A1D6188C000DA1F6A /* ScreenSelectorTests.xctest */,
161 | );
162 | name = Products;
163 | sourceTree = "";
164 | };
165 | 7520254D1D3F9A81000096E1 /* Resources */ = {
166 | isa = PBXGroup;
167 | children = (
168 | 7520254E1D3F9A88000096E1 /* image */,
169 | );
170 | name = Resources;
171 | sourceTree = "";
172 | };
173 | 7520254E1D3F9A88000096E1 /* image */ = {
174 | isa = PBXGroup;
175 | children = (
176 | 7520254F1D3F9AA5000096E1 /* example_bg@2x.jpg */,
177 | );
178 | name = image;
179 | sourceTree = "";
180 | };
181 | 75E4E1711D3F68A5001496FC = {
182 | isa = PBXGroup;
183 | children = (
184 | 75E4E17C1D3F68A5001496FC /* ScreenSelectorExample */,
185 | 75E4E1911D3F68A5001496FC /* ScreenSelectorExampleTests */,
186 | 75E4E19C1D3F68A5001496FC /* ScreenSelectorExampleUITests */,
187 | 75E4E17B1D3F68A5001496FC /* Products */,
188 | 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */,
189 | );
190 | sourceTree = "";
191 | };
192 | 75E4E17B1D3F68A5001496FC /* Products */ = {
193 | isa = PBXGroup;
194 | children = (
195 | 75E4E17A1D3F68A5001496FC /* ScreenSelectorExample.app */,
196 | 75E4E18E1D3F68A5001496FC /* ScreenSelectorExampleTests.xctest */,
197 | 75E4E1991D3F68A5001496FC /* ScreenSelectorExampleUITests.xctest */,
198 | );
199 | name = Products;
200 | sourceTree = "";
201 | };
202 | 75E4E17C1D3F68A5001496FC /* ScreenSelectorExample */ = {
203 | isa = PBXGroup;
204 | children = (
205 | 2D3850261D61909800DA1F6A /* ContentViewController.storyboard */,
206 | 2D3850271D61909800DA1F6A /* ContentViewController.swift */,
207 | 2D3850281D61909800DA1F6A /* DummyScreenGenerator.swift */,
208 | 75E4E17D1D3F68A5001496FC /* AppDelegate.swift */,
209 | 2D384FA91D6179D800DA1F6A /* ScreenSelectorView Example */,
210 | 2D384FA81D6179C400DA1F6A /* ScreenSelectorViewController Example */,
211 | 7520254D1D3F9A81000096E1 /* Resources */,
212 | 75E4E1841D3F68A5001496FC /* Assets.xcassets */,
213 | 75E4E1861D3F68A5001496FC /* LaunchScreen.storyboard */,
214 | 75E4E1891D3F68A5001496FC /* Info.plist */,
215 | );
216 | path = ScreenSelectorExample;
217 | sourceTree = "";
218 | };
219 | 75E4E1911D3F68A5001496FC /* ScreenSelectorExampleTests */ = {
220 | isa = PBXGroup;
221 | children = (
222 | 75E4E1921D3F68A5001496FC /* ScreenSelectorExampleTests.swift */,
223 | 75E4E1941D3F68A5001496FC /* Info.plist */,
224 | );
225 | path = ScreenSelectorExampleTests;
226 | sourceTree = "";
227 | };
228 | 75E4E19C1D3F68A5001496FC /* ScreenSelectorExampleUITests */ = {
229 | isa = PBXGroup;
230 | children = (
231 | 75E4E19D1D3F68A5001496FC /* ScreenSelectorExampleUITests.swift */,
232 | 75E4E19F1D3F68A5001496FC /* Info.plist */,
233 | );
234 | path = ScreenSelectorExampleUITests;
235 | sourceTree = "";
236 | };
237 | /* End PBXGroup section */
238 |
239 | /* Begin PBXNativeTarget section */
240 | 75E4E1791D3F68A5001496FC /* ScreenSelectorExample */ = {
241 | isa = PBXNativeTarget;
242 | buildConfigurationList = 75E4E1A21D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExample" */;
243 | buildPhases = (
244 | 75E4E1761D3F68A5001496FC /* Sources */,
245 | 75E4E1771D3F68A5001496FC /* Frameworks */,
246 | 75E4E1781D3F68A5001496FC /* Resources */,
247 | 7539D2CF1D463C8C003EAB79 /* Embed Frameworks */,
248 | 2D38501D1D61897800DA1F6A /* Copy Frameworks */,
249 | );
250 | buildRules = (
251 | );
252 | dependencies = (
253 | 2D38501C1D6188DC00DA1F6A /* PBXTargetDependency */,
254 | );
255 | name = ScreenSelectorExample;
256 | productName = ScreenSelectorExample;
257 | productReference = 75E4E17A1D3F68A5001496FC /* ScreenSelectorExample.app */;
258 | productType = "com.apple.product-type.application";
259 | };
260 | 75E4E18D1D3F68A5001496FC /* ScreenSelectorExampleTests */ = {
261 | isa = PBXNativeTarget;
262 | buildConfigurationList = 75E4E1A51D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExampleTests" */;
263 | buildPhases = (
264 | 75E4E18A1D3F68A5001496FC /* Sources */,
265 | 75E4E18B1D3F68A5001496FC /* Frameworks */,
266 | 75E4E18C1D3F68A5001496FC /* Resources */,
267 | );
268 | buildRules = (
269 | );
270 | dependencies = (
271 | 75E4E1901D3F68A5001496FC /* PBXTargetDependency */,
272 | );
273 | name = ScreenSelectorExampleTests;
274 | productName = ScreenSelectorExampleTests;
275 | productReference = 75E4E18E1D3F68A5001496FC /* ScreenSelectorExampleTests.xctest */;
276 | productType = "com.apple.product-type.bundle.unit-test";
277 | };
278 | 75E4E1981D3F68A5001496FC /* ScreenSelectorExampleUITests */ = {
279 | isa = PBXNativeTarget;
280 | buildConfigurationList = 75E4E1A81D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExampleUITests" */;
281 | buildPhases = (
282 | 75E4E1951D3F68A5001496FC /* Sources */,
283 | 75E4E1961D3F68A5001496FC /* Frameworks */,
284 | 75E4E1971D3F68A5001496FC /* Resources */,
285 | );
286 | buildRules = (
287 | );
288 | dependencies = (
289 | 75E4E19B1D3F68A5001496FC /* PBXTargetDependency */,
290 | );
291 | name = ScreenSelectorExampleUITests;
292 | productName = ScreenSelectorExampleUITests;
293 | productReference = 75E4E1991D3F68A5001496FC /* ScreenSelectorExampleUITests.xctest */;
294 | productType = "com.apple.product-type.bundle.ui-testing";
295 | };
296 | /* End PBXNativeTarget section */
297 |
298 | /* Begin PBXProject section */
299 | 75E4E1721D3F68A5001496FC /* Project object */ = {
300 | isa = PBXProject;
301 | attributes = {
302 | LastSwiftUpdateCheck = 0730;
303 | LastUpgradeCheck = 0730;
304 | ORGANIZATIONNAME = "Tomonori Ueno";
305 | TargetAttributes = {
306 | 75E4E1791D3F68A5001496FC = {
307 | CreatedOnToolsVersion = 7.3.1;
308 | };
309 | 75E4E18D1D3F68A5001496FC = {
310 | CreatedOnToolsVersion = 7.3.1;
311 | TestTargetID = 75E4E1791D3F68A5001496FC;
312 | };
313 | 75E4E1981D3F68A5001496FC = {
314 | CreatedOnToolsVersion = 7.3.1;
315 | TestTargetID = 75E4E1791D3F68A5001496FC;
316 | };
317 | };
318 | };
319 | buildConfigurationList = 75E4E1751D3F68A5001496FC /* Build configuration list for PBXProject "ScreenSelectorExample" */;
320 | compatibilityVersion = "Xcode 3.2";
321 | developmentRegion = English;
322 | hasScannedForEncodings = 0;
323 | knownRegions = (
324 | en,
325 | Base,
326 | );
327 | mainGroup = 75E4E1711D3F68A5001496FC;
328 | productRefGroup = 75E4E17B1D3F68A5001496FC /* Products */;
329 | projectDirPath = "";
330 | projectReferences = (
331 | {
332 | ProductGroup = 2D3850131D6188C000DA1F6A /* Products */;
333 | ProjectRef = 2D3850121D6188C000DA1F6A /* ScreenSelector.xcodeproj */;
334 | },
335 | );
336 | projectRoot = "";
337 | targets = (
338 | 75E4E1791D3F68A5001496FC /* ScreenSelectorExample */,
339 | 75E4E18D1D3F68A5001496FC /* ScreenSelectorExampleTests */,
340 | 75E4E1981D3F68A5001496FC /* ScreenSelectorExampleUITests */,
341 | );
342 | };
343 | /* End PBXProject section */
344 |
345 | /* Begin PBXReferenceProxy section */
346 | 2D3850181D6188C000DA1F6A /* ScreenSelector.framework */ = {
347 | isa = PBXReferenceProxy;
348 | fileType = wrapper.framework;
349 | path = ScreenSelector.framework;
350 | remoteRef = 2D3850171D6188C000DA1F6A /* PBXContainerItemProxy */;
351 | sourceTree = BUILT_PRODUCTS_DIR;
352 | };
353 | 2D38501A1D6188C000DA1F6A /* ScreenSelectorTests.xctest */ = {
354 | isa = PBXReferenceProxy;
355 | fileType = wrapper.cfbundle;
356 | path = ScreenSelectorTests.xctest;
357 | remoteRef = 2D3850191D6188C000DA1F6A /* PBXContainerItemProxy */;
358 | sourceTree = BUILT_PRODUCTS_DIR;
359 | };
360 | /* End PBXReferenceProxy section */
361 |
362 | /* Begin PBXResourcesBuildPhase section */
363 | 75E4E1781D3F68A5001496FC /* Resources */ = {
364 | isa = PBXResourcesBuildPhase;
365 | buildActionMask = 2147483647;
366 | files = (
367 | 75E4E1881D3F68A5001496FC /* LaunchScreen.storyboard in Resources */,
368 | 2D3850291D61909800DA1F6A /* ContentViewController.storyboard in Resources */,
369 | 75E4E1851D3F68A5001496FC /* Assets.xcassets in Resources */,
370 | 752025501D3F9AA5000096E1 /* example_bg@2x.jpg in Resources */,
371 | 75E4E1831D3F68A5001496FC /* ExtendedViewController.storyboard in Resources */,
372 | 2D38502F1D61BE6100DA1F6A /* ViewController.storyboard in Resources */,
373 | );
374 | runOnlyForDeploymentPostprocessing = 0;
375 | };
376 | 75E4E18C1D3F68A5001496FC /* Resources */ = {
377 | isa = PBXResourcesBuildPhase;
378 | buildActionMask = 2147483647;
379 | files = (
380 | );
381 | runOnlyForDeploymentPostprocessing = 0;
382 | };
383 | 75E4E1971D3F68A5001496FC /* Resources */ = {
384 | isa = PBXResourcesBuildPhase;
385 | buildActionMask = 2147483647;
386 | files = (
387 | );
388 | runOnlyForDeploymentPostprocessing = 0;
389 | };
390 | /* End PBXResourcesBuildPhase section */
391 |
392 | /* Begin PBXSourcesBuildPhase section */
393 | 75E4E1761D3F68A5001496FC /* Sources */ = {
394 | isa = PBXSourcesBuildPhase;
395 | buildActionMask = 2147483647;
396 | files = (
397 | 2D38502D1D61BE5600DA1F6A /* ViewController.swift in Sources */,
398 | 2D38502B1D61909800DA1F6A /* DummyScreenGenerator.swift in Sources */,
399 | 75E4E1801D3F68A5001496FC /* ExtendedViewController.swift in Sources */,
400 | 2D38502A1D61909800DA1F6A /* ContentViewController.swift in Sources */,
401 | 75E4E17E1D3F68A5001496FC /* AppDelegate.swift in Sources */,
402 | );
403 | runOnlyForDeploymentPostprocessing = 0;
404 | };
405 | 75E4E18A1D3F68A5001496FC /* Sources */ = {
406 | isa = PBXSourcesBuildPhase;
407 | buildActionMask = 2147483647;
408 | files = (
409 | 75E4E1931D3F68A5001496FC /* ScreenSelectorExampleTests.swift in Sources */,
410 | );
411 | runOnlyForDeploymentPostprocessing = 0;
412 | };
413 | 75E4E1951D3F68A5001496FC /* Sources */ = {
414 | isa = PBXSourcesBuildPhase;
415 | buildActionMask = 2147483647;
416 | files = (
417 | 75E4E19E1D3F68A5001496FC /* ScreenSelectorExampleUITests.swift in Sources */,
418 | );
419 | runOnlyForDeploymentPostprocessing = 0;
420 | };
421 | /* End PBXSourcesBuildPhase section */
422 |
423 | /* Begin PBXTargetDependency section */
424 | 2D38501C1D6188DC00DA1F6A /* PBXTargetDependency */ = {
425 | isa = PBXTargetDependency;
426 | name = ScreenSelector;
427 | targetProxy = 2D38501B1D6188DC00DA1F6A /* PBXContainerItemProxy */;
428 | };
429 | 75E4E1901D3F68A5001496FC /* PBXTargetDependency */ = {
430 | isa = PBXTargetDependency;
431 | target = 75E4E1791D3F68A5001496FC /* ScreenSelectorExample */;
432 | targetProxy = 75E4E18F1D3F68A5001496FC /* PBXContainerItemProxy */;
433 | };
434 | 75E4E19B1D3F68A5001496FC /* PBXTargetDependency */ = {
435 | isa = PBXTargetDependency;
436 | target = 75E4E1791D3F68A5001496FC /* ScreenSelectorExample */;
437 | targetProxy = 75E4E19A1D3F68A5001496FC /* PBXContainerItemProxy */;
438 | };
439 | /* End PBXTargetDependency section */
440 |
441 | /* Begin PBXVariantGroup section */
442 | 75E4E1811D3F68A5001496FC /* ExtendedViewController.storyboard */ = {
443 | isa = PBXVariantGroup;
444 | children = (
445 | 75E4E1821D3F68A5001496FC /* Base */,
446 | );
447 | name = ExtendedViewController.storyboard;
448 | sourceTree = "";
449 | };
450 | 75E4E1861D3F68A5001496FC /* LaunchScreen.storyboard */ = {
451 | isa = PBXVariantGroup;
452 | children = (
453 | 75E4E1871D3F68A5001496FC /* Base */,
454 | );
455 | name = LaunchScreen.storyboard;
456 | sourceTree = "";
457 | };
458 | /* End PBXVariantGroup section */
459 |
460 | /* Begin XCBuildConfiguration section */
461 | 75E4E1A01D3F68A5001496FC /* Debug */ = {
462 | isa = XCBuildConfiguration;
463 | buildSettings = {
464 | ALWAYS_SEARCH_USER_PATHS = NO;
465 | CLANG_ANALYZER_NONNULL = YES;
466 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
467 | CLANG_CXX_LIBRARY = "libc++";
468 | CLANG_ENABLE_MODULES = YES;
469 | CLANG_ENABLE_OBJC_ARC = YES;
470 | CLANG_WARN_BOOL_CONVERSION = YES;
471 | CLANG_WARN_CONSTANT_CONVERSION = YES;
472 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
473 | CLANG_WARN_EMPTY_BODY = YES;
474 | CLANG_WARN_ENUM_CONVERSION = YES;
475 | CLANG_WARN_INT_CONVERSION = YES;
476 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
477 | CLANG_WARN_UNREACHABLE_CODE = YES;
478 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
480 | COPY_PHASE_STRIP = NO;
481 | DEBUG_INFORMATION_FORMAT = dwarf;
482 | ENABLE_STRICT_OBJC_MSGSEND = YES;
483 | ENABLE_TESTABILITY = YES;
484 | GCC_C_LANGUAGE_STANDARD = gnu99;
485 | GCC_DYNAMIC_NO_PIC = NO;
486 | GCC_NO_COMMON_BLOCKS = YES;
487 | GCC_OPTIMIZATION_LEVEL = 0;
488 | GCC_PREPROCESSOR_DEFINITIONS = (
489 | "DEBUG=1",
490 | "$(inherited)",
491 | );
492 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
493 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
494 | GCC_WARN_UNDECLARED_SELECTOR = YES;
495 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
496 | GCC_WARN_UNUSED_FUNCTION = YES;
497 | GCC_WARN_UNUSED_VARIABLE = YES;
498 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
499 | MTL_ENABLE_DEBUG_INFO = YES;
500 | ONLY_ACTIVE_ARCH = YES;
501 | SDKROOT = iphoneos;
502 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
503 | };
504 | name = Debug;
505 | };
506 | 75E4E1A11D3F68A5001496FC /* Release */ = {
507 | isa = XCBuildConfiguration;
508 | buildSettings = {
509 | ALWAYS_SEARCH_USER_PATHS = NO;
510 | CLANG_ANALYZER_NONNULL = YES;
511 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
512 | CLANG_CXX_LIBRARY = "libc++";
513 | CLANG_ENABLE_MODULES = YES;
514 | CLANG_ENABLE_OBJC_ARC = YES;
515 | CLANG_WARN_BOOL_CONVERSION = YES;
516 | CLANG_WARN_CONSTANT_CONVERSION = YES;
517 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
518 | CLANG_WARN_EMPTY_BODY = YES;
519 | CLANG_WARN_ENUM_CONVERSION = YES;
520 | CLANG_WARN_INT_CONVERSION = YES;
521 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
522 | CLANG_WARN_UNREACHABLE_CODE = YES;
523 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
524 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
525 | COPY_PHASE_STRIP = NO;
526 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
527 | ENABLE_NS_ASSERTIONS = NO;
528 | ENABLE_STRICT_OBJC_MSGSEND = YES;
529 | GCC_C_LANGUAGE_STANDARD = gnu99;
530 | GCC_NO_COMMON_BLOCKS = YES;
531 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
532 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
533 | GCC_WARN_UNDECLARED_SELECTOR = YES;
534 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
535 | GCC_WARN_UNUSED_FUNCTION = YES;
536 | GCC_WARN_UNUSED_VARIABLE = YES;
537 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
538 | MTL_ENABLE_DEBUG_INFO = NO;
539 | SDKROOT = iphoneos;
540 | VALIDATE_PRODUCT = YES;
541 | };
542 | name = Release;
543 | };
544 | 75E4E1A31D3F68A5001496FC /* Debug */ = {
545 | isa = XCBuildConfiguration;
546 | buildSettings = {
547 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
548 | FRAMEWORK_SEARCH_PATHS = (
549 | "$(inherited)",
550 | "$(PROJECT_DIR)/ScreenSelectorExample",
551 | );
552 | INFOPLIST_FILE = ScreenSelectorExample/Info.plist;
553 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
554 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExample;
555 | PRODUCT_NAME = "$(TARGET_NAME)";
556 | };
557 | name = Debug;
558 | };
559 | 75E4E1A41D3F68A5001496FC /* Release */ = {
560 | isa = XCBuildConfiguration;
561 | buildSettings = {
562 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
563 | FRAMEWORK_SEARCH_PATHS = (
564 | "$(inherited)",
565 | "$(PROJECT_DIR)/ScreenSelectorExample",
566 | );
567 | INFOPLIST_FILE = ScreenSelectorExample/Info.plist;
568 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
569 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExample;
570 | PRODUCT_NAME = "$(TARGET_NAME)";
571 | };
572 | name = Release;
573 | };
574 | 75E4E1A61D3F68A5001496FC /* Debug */ = {
575 | isa = XCBuildConfiguration;
576 | buildSettings = {
577 | BUNDLE_LOADER = "$(TEST_HOST)";
578 | INFOPLIST_FILE = ScreenSelectorExampleTests/Info.plist;
579 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
580 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExampleTests;
581 | PRODUCT_NAME = "$(TARGET_NAME)";
582 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ScreenSelectorExample.app/ScreenSelectorExample";
583 | };
584 | name = Debug;
585 | };
586 | 75E4E1A71D3F68A5001496FC /* Release */ = {
587 | isa = XCBuildConfiguration;
588 | buildSettings = {
589 | BUNDLE_LOADER = "$(TEST_HOST)";
590 | INFOPLIST_FILE = ScreenSelectorExampleTests/Info.plist;
591 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
592 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExampleTests;
593 | PRODUCT_NAME = "$(TARGET_NAME)";
594 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ScreenSelectorExample.app/ScreenSelectorExample";
595 | };
596 | name = Release;
597 | };
598 | 75E4E1A91D3F68A5001496FC /* Debug */ = {
599 | isa = XCBuildConfiguration;
600 | buildSettings = {
601 | INFOPLIST_FILE = ScreenSelectorExampleUITests/Info.plist;
602 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
603 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExampleUITests;
604 | PRODUCT_NAME = "$(TARGET_NAME)";
605 | TEST_TARGET_NAME = ScreenSelectorExample;
606 | };
607 | name = Debug;
608 | };
609 | 75E4E1AA1D3F68A5001496FC /* Release */ = {
610 | isa = XCBuildConfiguration;
611 | buildSettings = {
612 | INFOPLIST_FILE = ScreenSelectorExampleUITests/Info.plist;
613 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
614 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorExampleUITests;
615 | PRODUCT_NAME = "$(TARGET_NAME)";
616 | TEST_TARGET_NAME = ScreenSelectorExample;
617 | };
618 | name = Release;
619 | };
620 | /* End XCBuildConfiguration section */
621 |
622 | /* Begin XCConfigurationList section */
623 | 75E4E1751D3F68A5001496FC /* Build configuration list for PBXProject "ScreenSelectorExample" */ = {
624 | isa = XCConfigurationList;
625 | buildConfigurations = (
626 | 75E4E1A01D3F68A5001496FC /* Debug */,
627 | 75E4E1A11D3F68A5001496FC /* Release */,
628 | );
629 | defaultConfigurationIsVisible = 0;
630 | defaultConfigurationName = Release;
631 | };
632 | 75E4E1A21D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExample" */ = {
633 | isa = XCConfigurationList;
634 | buildConfigurations = (
635 | 75E4E1A31D3F68A5001496FC /* Debug */,
636 | 75E4E1A41D3F68A5001496FC /* Release */,
637 | );
638 | defaultConfigurationIsVisible = 0;
639 | defaultConfigurationName = Release;
640 | };
641 | 75E4E1A51D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExampleTests" */ = {
642 | isa = XCConfigurationList;
643 | buildConfigurations = (
644 | 75E4E1A61D3F68A5001496FC /* Debug */,
645 | 75E4E1A71D3F68A5001496FC /* Release */,
646 | );
647 | defaultConfigurationIsVisible = 0;
648 | defaultConfigurationName = Release;
649 | };
650 | 75E4E1A81D3F68A5001496FC /* Build configuration list for PBXNativeTarget "ScreenSelectorExampleUITests" */ = {
651 | isa = XCConfigurationList;
652 | buildConfigurations = (
653 | 75E4E1A91D3F68A5001496FC /* Debug */,
654 | 75E4E1AA1D3F68A5001496FC /* Release */,
655 | );
656 | defaultConfigurationIsVisible = 0;
657 | defaultConfigurationName = Release;
658 | };
659 | /* End XCConfigurationList section */
660 | };
661 | rootObject = 75E4E1721D3F68A5001496FC /* Project object */;
662 | }
663 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample.xcodeproj/xcshareddata/xcschemes/ScreenSelectorExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/20.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | return true
19 | }
20 |
21 | func applicationWillResignActive(application: UIApplication) {
22 | }
23 |
24 | func applicationDidEnterBackground(application: UIApplication) {
25 | }
26 |
27 | func applicationWillEnterForeground(application: UIApplication) {
28 | }
29 |
30 | func applicationDidBecomeActive(application: UIApplication) {
31 | }
32 |
33 | func applicationWillTerminate(application: UIApplication) {
34 | }
35 |
36 |
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/Base.lproj/ExtendedViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/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 |
27 |
28 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/ExtendedViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExtendedViewController.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/20.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ScreenSelector
11 |
12 | final class ExtendedViewController: ScreenSelectorViewController {
13 |
14 | @IBOutlet weak var sampleImageView: UIImageView!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | self.screenSelectorView.previewReflectionEnabled = true
19 | self.previewableScreens = DummyScreenGenerator.generateViewControllers()
20 | self.screenSelectorView.reloadData()
21 | }
22 |
23 | override func viewDidAppear(animated: Bool) {
24 | super.viewDidAppear(animated)
25 | }
26 |
27 | override func didReceiveMemoryWarning() {
28 | super.didReceiveMemoryWarning()
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | ViewController
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/ViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
30 |
31 |
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 |
61 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori on 2016/08/15.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ScreenSelector
11 |
12 | final class ViewController: UIViewController, ScreenSelectorViewDelegate, ScreenSelectorViewDataSource, UIViewControllerTransitioningDelegate {
13 |
14 | @IBOutlet weak var screenSelectorView: ScreenSelectorView!
15 | private var previewableScreens: [ScreenSelectorPreviewable] = []
16 |
17 | weak var transitionFromPreviewImageView: UIImageView?
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 | previewableScreens = DummyScreenGenerator.generateViewControllers()
22 | screenSelectorView.delegate = self
23 | screenSelectorView.dataSource = self
24 | }
25 |
26 | override func viewDidAppear(animated: Bool) {
27 | super.viewDidAppear(animated)
28 | }
29 |
30 | // MARK: - ScreenSelectorView Delegate
31 |
32 | func screenSelectorViewDidTapScreenAtIndex(index: Int, previewView: ScreenPreviewViewProtocol) {
33 | transitionFromPreviewImageView = previewView.imageView
34 | if let viewController = previewableScreens[index] as? UIViewController {
35 | viewController.transitioningDelegate = self
36 | presentViewController(viewController, animated: true) {
37 | // Move selected preview to center of screen.
38 | self.screenSelectorView.scrollToIndex(index, animated: false)
39 | }
40 | }
41 | }
42 |
43 | // MARK: - ScreenSelectorView DataSource
44 |
45 | func numberOfScreens() -> Int {
46 | return previewableScreens.count
47 | }
48 |
49 | func previewViewForScreenAtIndex(index: Int) -> ScreenPreviewViewProtocol {
50 | let size = CGSize(width: UIScreen.mainScreen().bounds.width * 0.6, height: UIScreen.mainScreen().bounds.height * 0.6)
51 | let screenView = ScreenPreviewView(frame: CGRect(origin: CGPoint.zero, size: size))
52 | let previewable = previewableScreens[index]
53 | let previewImage: UIImage? = previewable.thumbnailImage
54 | guard let vc = previewable as? UIViewController else {
55 | fatalError()
56 | }
57 | let titleText: String? = vc.title
58 | screenView.titleLabel.text = titleText
59 | screenView.imageView.image = previewImage
60 | return screenView
61 | }
62 |
63 | // MARK: -
64 |
65 | func animationControllerForPresentedController(presented: UIViewController,
66 | presentingController presenting: UIViewController,
67 | sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
68 | let animator = ScreenSelectorTransitioningAnimator(isReverse: false, moveFromImageView: transitionFromPreviewImageView)
69 | return animator
70 | }
71 |
72 | func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
73 | let animator = ScreenSelectorTransitioningAnimator(isReverse: true, moveFromImageView: transitionFromPreviewImageView)
74 | return animator
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExample/example_bg@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tueno/ScreenSelector/11eeacd66d52c4673e695cafacfe060f25cefc6e/Example/ScreenSelectorExample/example_bg@2x.jpg
--------------------------------------------------------------------------------
/Example/ScreenSelectorExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExampleTests/ScreenSelectorExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorExampleTests.swift
3 | // ScreenSelectorExampleTests
4 | //
5 | // Created by Tomonori Ueno on 2016/07/20.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ScreenSelectorExample
11 |
12 | class ScreenSelectorExampleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExampleUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/ScreenSelectorExampleUITests/ScreenSelectorExampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorExampleUITests.swift
3 | // ScreenSelectorExampleUITests
4 | //
5 | // Created by Tomonori Ueno on 2016/07/20.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class ScreenSelectorExampleUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Tueno
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ScreenSelector
2 |
3 | Provides screen selector UI for iOS.
4 |
5 | 
6 |
7 | ## Feature
8 | ### ScreenSelectorView
9 | * IBDesignable supporting.
10 | * IBInspectable supporting.
11 | * Can use your custom preview view that is compatible with ScreenPreviewViewProtocol.
12 | * Can show preview view's specular reflection.
13 |
14 | ### ScreenSelectorViewController
15 | * Wrapper class of `ScreenSelectorView`.
16 | * Easy to use.
17 |
18 | ## Usage
19 |
20 | * Extend `ScreenSelectorViewController` and set `UIViewController` instance that conforms to `ScreenSelectorPreviewable` protocol to `previewableScreens` property.
21 |
22 | OR
23 |
24 | * Add `ScreenSelectorView` instance to any view and set `dataSource` and `delegate`. (You can use custom preview view class.)
25 |
26 | (See `Example` for details.)
27 |
28 | ## Requirements
29 |
30 | * iOS8.0+
31 | * Xcode7.3+
32 |
33 | ## Installation
34 |
35 | ### Carthage
36 |
37 | Add this line to your Cartfile.
38 | ```ogdl
39 | github "Tueno/ScreenSelector"
40 | ```
41 |
42 |
--------------------------------------------------------------------------------
/ScreenSelector.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2D384F991D6177E200DA1F6A /* ScreenSelector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D384F8E1D6177E200DA1F6A /* ScreenSelector.framework */; };
11 | 2D384F9E1D6177E200DA1F6A /* ScreenSelectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384F9D1D6177E200DA1F6A /* ScreenSelectorTests.swift */; };
12 | 2D384FB21D617A8200DA1F6A /* DummyScreenGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAA1D617A8200DA1F6A /* DummyScreenGenerator.swift */; };
13 | 2D384FB31D617A8200DA1F6A /* ReversibleAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAB1D617A8200DA1F6A /* ReversibleAnimatedTransitioning.swift */; };
14 | 2D384FB41D617A8200DA1F6A /* ScreenPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAC1D617A8200DA1F6A /* ScreenPreviewView.swift */; };
15 | 2D384FB51D617A8200DA1F6A /* ScreenSelectorPreviewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAD1D617A8200DA1F6A /* ScreenSelectorPreviewable.swift */; };
16 | 2D384FB61D617A8200DA1F6A /* ScreenSelectorTransitioningAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAE1D617A8200DA1F6A /* ScreenSelectorTransitioningAnimator.swift */; };
17 | 2D384FB71D617A8200DA1F6A /* ScreenSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FAF1D617A8200DA1F6A /* ScreenSelectorView.swift */; };
18 | 2D384FB81D617A8200DA1F6A /* ScreenSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FB01D617A8200DA1F6A /* ScreenSelectorViewController.swift */; };
19 | 2D384FB91D617A8200DA1F6A /* SpecularReflectionLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D384FB11D617A8200DA1F6A /* SpecularReflectionLayer.swift */; };
20 | 2D384FFD1D6184A500DA1F6A /* ScreenSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D384FFC1D61842100DA1F6A /* ScreenSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXContainerItemProxy section */
24 | 2D384F9A1D6177E200DA1F6A /* PBXContainerItemProxy */ = {
25 | isa = PBXContainerItemProxy;
26 | containerPortal = 2D384F851D6177E200DA1F6A /* Project object */;
27 | proxyType = 1;
28 | remoteGlobalIDString = 2D384F8D1D6177E200DA1F6A;
29 | remoteInfo = ScreenSelector;
30 | };
31 | /* End PBXContainerItemProxy section */
32 |
33 | /* Begin PBXFileReference section */
34 | 2D384F8E1D6177E200DA1F6A /* ScreenSelector.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ScreenSelector.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 2D384F931D6177E200DA1F6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
36 | 2D384F981D6177E200DA1F6A /* ScreenSelectorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScreenSelectorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
37 | 2D384F9D1D6177E200DA1F6A /* ScreenSelectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSelectorTests.swift; sourceTree = ""; };
38 | 2D384F9F1D6177E200DA1F6A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
39 | 2D384FAA1D617A8200DA1F6A /* DummyScreenGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DummyScreenGenerator.swift; sourceTree = ""; };
40 | 2D384FAB1D617A8200DA1F6A /* ReversibleAnimatedTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReversibleAnimatedTransitioning.swift; sourceTree = ""; };
41 | 2D384FAC1D617A8200DA1F6A /* ScreenPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenPreviewView.swift; sourceTree = ""; };
42 | 2D384FAD1D617A8200DA1F6A /* ScreenSelectorPreviewable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSelectorPreviewable.swift; sourceTree = ""; };
43 | 2D384FAE1D617A8200DA1F6A /* ScreenSelectorTransitioningAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSelectorTransitioningAnimator.swift; sourceTree = ""; };
44 | 2D384FAF1D617A8200DA1F6A /* ScreenSelectorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSelectorView.swift; sourceTree = ""; };
45 | 2D384FB01D617A8200DA1F6A /* ScreenSelectorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSelectorViewController.swift; sourceTree = ""; };
46 | 2D384FB11D617A8200DA1F6A /* SpecularReflectionLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecularReflectionLayer.swift; sourceTree = ""; };
47 | 2D384FFC1D61842100DA1F6A /* ScreenSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScreenSelector.h; sourceTree = ""; };
48 | /* End PBXFileReference section */
49 |
50 | /* Begin PBXFrameworksBuildPhase section */
51 | 2D384F8A1D6177E200DA1F6A /* Frameworks */ = {
52 | isa = PBXFrameworksBuildPhase;
53 | buildActionMask = 2147483647;
54 | files = (
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | 2D384F951D6177E200DA1F6A /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 2D384F991D6177E200DA1F6A /* ScreenSelector.framework in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 2D384F841D6177E200DA1F6A = {
70 | isa = PBXGroup;
71 | children = (
72 | 2D384F901D6177E200DA1F6A /* ScreenSelector */,
73 | 2D384F9C1D6177E200DA1F6A /* ScreenSelectorTests */,
74 | 2D384F8F1D6177E200DA1F6A /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 2D384F8F1D6177E200DA1F6A /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 2D384F8E1D6177E200DA1F6A /* ScreenSelector.framework */,
82 | 2D384F981D6177E200DA1F6A /* ScreenSelectorTests.xctest */,
83 | );
84 | name = Products;
85 | sourceTree = "";
86 | };
87 | 2D384F901D6177E200DA1F6A /* ScreenSelector */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 2D384FBE1D617AD600DA1F6A /* Dummy */,
91 | 2D384FAB1D617A8200DA1F6A /* ReversibleAnimatedTransitioning.swift */,
92 | 2D384FAC1D617A8200DA1F6A /* ScreenPreviewView.swift */,
93 | 2D384FAD1D617A8200DA1F6A /* ScreenSelectorPreviewable.swift */,
94 | 2D384FAE1D617A8200DA1F6A /* ScreenSelectorTransitioningAnimator.swift */,
95 | 2D384FAF1D617A8200DA1F6A /* ScreenSelectorView.swift */,
96 | 2D384FB01D617A8200DA1F6A /* ScreenSelectorViewController.swift */,
97 | 2D384FB11D617A8200DA1F6A /* SpecularReflectionLayer.swift */,
98 | 2D384F931D6177E200DA1F6A /* Info.plist */,
99 | 2D384FFC1D61842100DA1F6A /* ScreenSelector.h */,
100 | );
101 | path = ScreenSelector;
102 | sourceTree = "";
103 | };
104 | 2D384F9C1D6177E200DA1F6A /* ScreenSelectorTests */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 2D384F9D1D6177E200DA1F6A /* ScreenSelectorTests.swift */,
108 | 2D384F9F1D6177E200DA1F6A /* Info.plist */,
109 | );
110 | path = ScreenSelectorTests;
111 | sourceTree = "";
112 | };
113 | 2D384FBE1D617AD600DA1F6A /* Dummy */ = {
114 | isa = PBXGroup;
115 | children = (
116 | 2D384FAA1D617A8200DA1F6A /* DummyScreenGenerator.swift */,
117 | );
118 | name = Dummy;
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXHeadersBuildPhase section */
124 | 2D384F8B1D6177E200DA1F6A /* Headers */ = {
125 | isa = PBXHeadersBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | 2D384FFD1D6184A500DA1F6A /* ScreenSelector.h in Headers */,
129 | );
130 | runOnlyForDeploymentPostprocessing = 0;
131 | };
132 | /* End PBXHeadersBuildPhase section */
133 |
134 | /* Begin PBXNativeTarget section */
135 | 2D384F8D1D6177E200DA1F6A /* ScreenSelector */ = {
136 | isa = PBXNativeTarget;
137 | buildConfigurationList = 2D384FA21D6177E200DA1F6A /* Build configuration list for PBXNativeTarget "ScreenSelector" */;
138 | buildPhases = (
139 | 2D384F891D6177E200DA1F6A /* Sources */,
140 | 2D384F8A1D6177E200DA1F6A /* Frameworks */,
141 | 2D384F8B1D6177E200DA1F6A /* Headers */,
142 | 2D384F8C1D6177E200DA1F6A /* Resources */,
143 | );
144 | buildRules = (
145 | );
146 | dependencies = (
147 | );
148 | name = ScreenSelector;
149 | productName = ScreenSelector;
150 | productReference = 2D384F8E1D6177E200DA1F6A /* ScreenSelector.framework */;
151 | productType = "com.apple.product-type.framework";
152 | };
153 | 2D384F971D6177E200DA1F6A /* ScreenSelectorTests */ = {
154 | isa = PBXNativeTarget;
155 | buildConfigurationList = 2D384FA51D6177E200DA1F6A /* Build configuration list for PBXNativeTarget "ScreenSelectorTests" */;
156 | buildPhases = (
157 | 2D384F941D6177E200DA1F6A /* Sources */,
158 | 2D384F951D6177E200DA1F6A /* Frameworks */,
159 | 2D384F961D6177E200DA1F6A /* Resources */,
160 | );
161 | buildRules = (
162 | );
163 | dependencies = (
164 | 2D384F9B1D6177E200DA1F6A /* PBXTargetDependency */,
165 | );
166 | name = ScreenSelectorTests;
167 | productName = ScreenSelectorTests;
168 | productReference = 2D384F981D6177E200DA1F6A /* ScreenSelectorTests.xctest */;
169 | productType = "com.apple.product-type.bundle.unit-test";
170 | };
171 | /* End PBXNativeTarget section */
172 |
173 | /* Begin PBXProject section */
174 | 2D384F851D6177E200DA1F6A /* Project object */ = {
175 | isa = PBXProject;
176 | attributes = {
177 | LastSwiftUpdateCheck = 0730;
178 | LastUpgradeCheck = 0730;
179 | ORGANIZATIONNAME = "Tomonori Ueno";
180 | TargetAttributes = {
181 | 2D384F8D1D6177E200DA1F6A = {
182 | CreatedOnToolsVersion = 7.3.1;
183 | };
184 | 2D384F971D6177E200DA1F6A = {
185 | CreatedOnToolsVersion = 7.3.1;
186 | };
187 | };
188 | };
189 | buildConfigurationList = 2D384F881D6177E200DA1F6A /* Build configuration list for PBXProject "ScreenSelector" */;
190 | compatibilityVersion = "Xcode 3.2";
191 | developmentRegion = English;
192 | hasScannedForEncodings = 0;
193 | knownRegions = (
194 | en,
195 | );
196 | mainGroup = 2D384F841D6177E200DA1F6A;
197 | productRefGroup = 2D384F8F1D6177E200DA1F6A /* Products */;
198 | projectDirPath = "";
199 | projectRoot = "";
200 | targets = (
201 | 2D384F8D1D6177E200DA1F6A /* ScreenSelector */,
202 | 2D384F971D6177E200DA1F6A /* ScreenSelectorTests */,
203 | );
204 | };
205 | /* End PBXProject section */
206 |
207 | /* Begin PBXResourcesBuildPhase section */
208 | 2D384F8C1D6177E200DA1F6A /* Resources */ = {
209 | isa = PBXResourcesBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | 2D384F961D6177E200DA1F6A /* Resources */ = {
216 | isa = PBXResourcesBuildPhase;
217 | buildActionMask = 2147483647;
218 | files = (
219 | );
220 | runOnlyForDeploymentPostprocessing = 0;
221 | };
222 | /* End PBXResourcesBuildPhase section */
223 |
224 | /* Begin PBXSourcesBuildPhase section */
225 | 2D384F891D6177E200DA1F6A /* Sources */ = {
226 | isa = PBXSourcesBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | 2D384FB41D617A8200DA1F6A /* ScreenPreviewView.swift in Sources */,
230 | 2D384FB61D617A8200DA1F6A /* ScreenSelectorTransitioningAnimator.swift in Sources */,
231 | 2D384FB81D617A8200DA1F6A /* ScreenSelectorViewController.swift in Sources */,
232 | 2D384FB51D617A8200DA1F6A /* ScreenSelectorPreviewable.swift in Sources */,
233 | 2D384FB21D617A8200DA1F6A /* DummyScreenGenerator.swift in Sources */,
234 | 2D384FB31D617A8200DA1F6A /* ReversibleAnimatedTransitioning.swift in Sources */,
235 | 2D384FB71D617A8200DA1F6A /* ScreenSelectorView.swift in Sources */,
236 | 2D384FB91D617A8200DA1F6A /* SpecularReflectionLayer.swift in Sources */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | 2D384F941D6177E200DA1F6A /* Sources */ = {
241 | isa = PBXSourcesBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | 2D384F9E1D6177E200DA1F6A /* ScreenSelectorTests.swift in Sources */,
245 | );
246 | runOnlyForDeploymentPostprocessing = 0;
247 | };
248 | /* End PBXSourcesBuildPhase section */
249 |
250 | /* Begin PBXTargetDependency section */
251 | 2D384F9B1D6177E200DA1F6A /* PBXTargetDependency */ = {
252 | isa = PBXTargetDependency;
253 | target = 2D384F8D1D6177E200DA1F6A /* ScreenSelector */;
254 | targetProxy = 2D384F9A1D6177E200DA1F6A /* PBXContainerItemProxy */;
255 | };
256 | /* End PBXTargetDependency section */
257 |
258 | /* Begin XCBuildConfiguration section */
259 | 2D384FA01D6177E200DA1F6A /* Debug */ = {
260 | isa = XCBuildConfiguration;
261 | buildSettings = {
262 | ALWAYS_SEARCH_USER_PATHS = NO;
263 | CLANG_ANALYZER_NONNULL = YES;
264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
265 | CLANG_CXX_LIBRARY = "libc++";
266 | CLANG_ENABLE_MODULES = YES;
267 | CLANG_ENABLE_OBJC_ARC = YES;
268 | CLANG_WARN_BOOL_CONVERSION = YES;
269 | CLANG_WARN_CONSTANT_CONVERSION = YES;
270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
271 | CLANG_WARN_EMPTY_BODY = YES;
272 | CLANG_WARN_ENUM_CONVERSION = YES;
273 | CLANG_WARN_INT_CONVERSION = YES;
274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
275 | CLANG_WARN_UNREACHABLE_CODE = YES;
276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
278 | COPY_PHASE_STRIP = NO;
279 | CURRENT_PROJECT_VERSION = 1;
280 | DEBUG_INFORMATION_FORMAT = dwarf;
281 | ENABLE_BITCODE = NO;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | ENABLE_TESTABILITY = YES;
284 | GCC_C_LANGUAGE_STANDARD = gnu99;
285 | GCC_DYNAMIC_NO_PIC = NO;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_OPTIMIZATION_LEVEL = 0;
288 | GCC_PREPROCESSOR_DEFINITIONS = (
289 | "DEBUG=1",
290 | "$(inherited)",
291 | );
292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
294 | GCC_WARN_UNDECLARED_SELECTOR = YES;
295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
296 | GCC_WARN_UNUSED_FUNCTION = YES;
297 | GCC_WARN_UNUSED_VARIABLE = YES;
298 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
299 | MTL_ENABLE_DEBUG_INFO = YES;
300 | ONLY_ACTIVE_ARCH = YES;
301 | SDKROOT = iphoneos;
302 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | VERSIONING_SYSTEM = "apple-generic";
305 | VERSION_INFO_PREFIX = "";
306 | };
307 | name = Debug;
308 | };
309 | 2D384FA11D6177E200DA1F6A /* Release */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | ALWAYS_SEARCH_USER_PATHS = NO;
313 | CLANG_ANALYZER_NONNULL = YES;
314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
315 | CLANG_CXX_LIBRARY = "libc++";
316 | CLANG_ENABLE_MODULES = YES;
317 | CLANG_ENABLE_OBJC_ARC = YES;
318 | CLANG_WARN_BOOL_CONVERSION = YES;
319 | CLANG_WARN_CONSTANT_CONVERSION = YES;
320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
321 | CLANG_WARN_EMPTY_BODY = YES;
322 | CLANG_WARN_ENUM_CONVERSION = YES;
323 | CLANG_WARN_INT_CONVERSION = YES;
324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
325 | CLANG_WARN_UNREACHABLE_CODE = YES;
326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
327 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
328 | COPY_PHASE_STRIP = NO;
329 | CURRENT_PROJECT_VERSION = 1;
330 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
331 | ENABLE_BITCODE = NO;
332 | ENABLE_NS_ASSERTIONS = NO;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | GCC_C_LANGUAGE_STANDARD = gnu99;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_OPTIMIZATION_LEVEL = 0;
337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
339 | GCC_WARN_UNDECLARED_SELECTOR = YES;
340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
341 | GCC_WARN_UNUSED_FUNCTION = YES;
342 | GCC_WARN_UNUSED_VARIABLE = YES;
343 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
344 | MTL_ENABLE_DEBUG_INFO = NO;
345 | SDKROOT = iphoneos;
346 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
347 | TARGETED_DEVICE_FAMILY = "1,2";
348 | VALIDATE_PRODUCT = YES;
349 | VERSIONING_SYSTEM = "apple-generic";
350 | VERSION_INFO_PREFIX = "";
351 | };
352 | name = Release;
353 | };
354 | 2D384FA31D6177E200DA1F6A /* Debug */ = {
355 | isa = XCBuildConfiguration;
356 | buildSettings = {
357 | APPLICATION_EXTENSION_API_ONLY = NO;
358 | CLANG_ENABLE_MODULES = YES;
359 | DEFINES_MODULE = YES;
360 | DYLIB_COMPATIBILITY_VERSION = 1;
361 | DYLIB_CURRENT_VERSION = 1;
362 | DYLIB_INSTALL_NAME_BASE = "@rpath";
363 | INFOPLIST_FILE = ScreenSelector/Info.plist;
364 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
366 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelector;
367 | PRODUCT_NAME = "$(TARGET_NAME)";
368 | SKIP_INSTALL = YES;
369 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
370 | };
371 | name = Debug;
372 | };
373 | 2D384FA41D6177E200DA1F6A /* Release */ = {
374 | isa = XCBuildConfiguration;
375 | buildSettings = {
376 | APPLICATION_EXTENSION_API_ONLY = NO;
377 | CLANG_ENABLE_MODULES = YES;
378 | DEFINES_MODULE = YES;
379 | DYLIB_COMPATIBILITY_VERSION = 1;
380 | DYLIB_CURRENT_VERSION = 1;
381 | DYLIB_INSTALL_NAME_BASE = "@rpath";
382 | INFOPLIST_FILE = ScreenSelector/Info.plist;
383 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
385 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelector;
386 | PRODUCT_NAME = "$(TARGET_NAME)";
387 | SKIP_INSTALL = YES;
388 | };
389 | name = Release;
390 | };
391 | 2D384FA61D6177E200DA1F6A /* Debug */ = {
392 | isa = XCBuildConfiguration;
393 | buildSettings = {
394 | INFOPLIST_FILE = ScreenSelectorTests/Info.plist;
395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
396 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorTests;
397 | PRODUCT_NAME = "$(TARGET_NAME)";
398 | };
399 | name = Debug;
400 | };
401 | 2D384FA71D6177E200DA1F6A /* Release */ = {
402 | isa = XCBuildConfiguration;
403 | buildSettings = {
404 | INFOPLIST_FILE = ScreenSelectorTests/Info.plist;
405 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
406 | PRODUCT_BUNDLE_IDENTIFIER = com.tueno.ScreenSelectorTests;
407 | PRODUCT_NAME = "$(TARGET_NAME)";
408 | };
409 | name = Release;
410 | };
411 | /* End XCBuildConfiguration section */
412 |
413 | /* Begin XCConfigurationList section */
414 | 2D384F881D6177E200DA1F6A /* Build configuration list for PBXProject "ScreenSelector" */ = {
415 | isa = XCConfigurationList;
416 | buildConfigurations = (
417 | 2D384FA01D6177E200DA1F6A /* Debug */,
418 | 2D384FA11D6177E200DA1F6A /* Release */,
419 | );
420 | defaultConfigurationIsVisible = 0;
421 | defaultConfigurationName = Release;
422 | };
423 | 2D384FA21D6177E200DA1F6A /* Build configuration list for PBXNativeTarget "ScreenSelector" */ = {
424 | isa = XCConfigurationList;
425 | buildConfigurations = (
426 | 2D384FA31D6177E200DA1F6A /* Debug */,
427 | 2D384FA41D6177E200DA1F6A /* Release */,
428 | );
429 | defaultConfigurationIsVisible = 0;
430 | defaultConfigurationName = Release;
431 | };
432 | 2D384FA51D6177E200DA1F6A /* Build configuration list for PBXNativeTarget "ScreenSelectorTests" */ = {
433 | isa = XCConfigurationList;
434 | buildConfigurations = (
435 | 2D384FA61D6177E200DA1F6A /* Debug */,
436 | 2D384FA71D6177E200DA1F6A /* Release */,
437 | );
438 | defaultConfigurationIsVisible = 0;
439 | defaultConfigurationName = Release;
440 | };
441 | /* End XCConfigurationList section */
442 | };
443 | rootObject = 2D384F851D6177E200DA1F6A /* Project object */;
444 | }
445 |
--------------------------------------------------------------------------------
/ScreenSelector.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ScreenSelector.xcodeproj/xcshareddata/xcschemes/ScreenSelector.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/ScreenSelector/DummyScreenGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DummyScreenGenerator.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/26.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class DummyScreenGenerator {
12 |
13 | class func generateViews() -> [ScreenSelectorPreviewable] {
14 | var views = [ScreenSelectorPreviewable]()
15 | for _ in 0.stride(to: 5, by: 1) {
16 | let view = DummyView()
17 | views.append(view)
18 | }
19 | return views
20 | }
21 |
22 | }
23 |
24 | final class DummyScreenDataSource: ScreenSelectorViewDataSource {
25 |
26 | let dummyScreeens = DummyScreenGenerator.generateViews()
27 | func previewViewForScreenAtIndex(index: Int) -> ScreenPreviewViewProtocol {
28 | let size = CGSize(width: UIScreen.mainScreen().bounds.width * 0.6, height: UIScreen.mainScreen().bounds.height * 0.6)
29 | let screenView = ScreenPreviewView(frame: CGRect(origin: CGPoint.zero, size: size))
30 | let previewable = dummyScreeens[index]
31 | let previewImage: UIImage? = previewable.thumbnailImage
32 | let titleText: String? = "Title"
33 | screenView.titleLabel.text = titleText
34 | screenView.imageView.image = previewImage
35 | return screenView
36 | }
37 |
38 | func numberOfScreens() -> Int {
39 | return dummyScreeens.count
40 | }
41 |
42 | }
43 |
44 | final class DummyView: UIView, ScreenSelectorPreviewable {
45 |
46 | @IBOutlet weak var backgroundImageView: UIImageView?
47 | var thumbnailImage: UIImage? {
48 | get {
49 | UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen().bounds.size, false, 0)
50 | if let context = UIGraphicsGetCurrentContext() {
51 | let path = UIBezierPath(rect: UIScreen.mainScreen().bounds)
52 | path.lineWidth = 4
53 | path.stroke()
54 | CGContextAddPath(context, path.CGPath)
55 | let image = UIGraphicsGetImageFromCurrentImageContext()
56 | UIGraphicsEndImageContext()
57 | return image
58 | } else {
59 | UIGraphicsEndImageContext()
60 | return nil
61 | }
62 | }
63 | }
64 | var title: String? = "Title"
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/ScreenSelector/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ScreenSelector/ReversibleAnimatedTransitioning.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReversibleAnimatedTransitioning.swift
3 | // Oder
4 | //
5 | // Created by Tomonori Ueno on 2016/05/10.
6 | // Copyright © 2016年 Showcase Gig Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol ReversibleAnimatedTransitioning: UIViewControllerAnimatedTransitioning {
12 |
13 | var isReverse: Bool { get set }
14 | init()
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenPreviewView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenPreviewView.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/22.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol ScreenPreviewViewProtocol: class {
12 | var titleLabel: UILabel! { get set }
13 | var imageView: UIImageView! { get set }
14 | }
15 |
16 | public class ScreenPreviewView: UIView, ScreenPreviewViewProtocol {
17 |
18 | public var titleLabel: UILabel! = UILabel()
19 | public var imageView: UIImageView! = UIImageView()
20 |
21 | public override init(frame: CGRect) {
22 | super.init(frame: frame)
23 | setupSubviews()
24 | }
25 |
26 | required public init?(coder aDecoder: NSCoder) {
27 | fatalError("init(coder:) has not been implemented")
28 | }
29 |
30 | private func setupSubviews() {
31 | let imageAreaRatio: CGFloat = 0.9
32 | var titleLabelFrame = titleLabel.frame
33 | titleLabelFrame.origin.y = 0
34 | titleLabelFrame.size.height = bounds.height * (1-imageAreaRatio)
35 | titleLabelFrame.size.width = bounds.width * imageAreaRatio
36 | titleLabel.frame = titleLabelFrame
37 | titleLabel.center = CGPoint(x: bounds.midX, y: titleLabel.center.y)
38 | titleLabel.textAlignment = .Center
39 | var imageViewFrame = imageView.frame
40 | imageViewFrame.size.height = bounds.height * imageAreaRatio
41 | imageViewFrame.size.width = bounds.width * imageAreaRatio
42 | imageViewFrame.origin.y = titleLabel.frame.maxY
43 | imageView.frame = imageViewFrame
44 | imageView.center = CGPoint(x: bounds.width * 0.5, y: imageView.center.y)
45 | imageView.contentMode = .ScaleAspectFill
46 | imageView.layer.masksToBounds = true
47 | addSubview(titleLabel)
48 | addSubview(imageView)
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenSelector.h:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelector.h
3 | // ScreenSelector
4 | //
5 | // Created by Tomonori on 2016/08/15.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ScreenSelector.
12 | FOUNDATION_EXPORT double ScreenSelectorVersionNumber;
13 |
14 | //! Project version string for ScreenSelector.
15 | FOUNDATION_EXPORT const unsigned char ScreenSelectorVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenSelectorPreviewable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorPreviewable.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/22.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol ScreenSelectorPreviewable: class {
12 | var thumbnailImage: UIImage? { get }
13 | var backgroundImageView: UIImageView? { get }
14 | }
15 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenSelectorTransitioningAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorTransitioningAnimator.swift
3 | //
4 | // Created by Tomonori Ueno on 2016/05/10.
5 | // Copyright © 2016年 Tomonori Ueno All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | final public class ScreenSelectorTransitioningAnimator: NSObject, ReversibleAnimatedTransitioning {
11 |
12 | weak var moveFromImageView: UIImageView?
13 | public var isReverse: Bool
14 |
15 | override required public init() {
16 | isReverse = false
17 | super.init()
18 | }
19 |
20 | required public init(isReverse: Bool = false, moveFromImageView: UIImageView?) {
21 | self.isReverse = isReverse
22 | self.moveFromImageView = moveFromImageView
23 | super.init()
24 | }
25 |
26 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
27 | return 0.6
28 | }
29 |
30 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
31 |
32 | guard let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
33 | toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey),
34 | containerView = transitionContext.containerView() else {
35 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
36 | return
37 | }
38 |
39 | let fromView = fromVC.view
40 | let toView = toVC.view
41 | let generateCopyOfImageView: UIImageView? -> UIImageView? = { view in
42 | guard let view = view else {
43 | return nil
44 | }
45 | toView.layoutIfNeeded()
46 | let copy = UIImageView(image: view.image)
47 | copy.contentMode = view.contentMode
48 | copy.frame = containerView.convertRect(view.frame, fromView: view.superview)
49 | copy.layer.masksToBounds = true
50 | return copy
51 | }
52 | if toView.frame == CGRect.zero {
53 | toView.frame = fromView.frame
54 | }
55 | let copiedImageView: UIImageView?
56 | let moveFromView: UIView?
57 | let moveToView: UIView?
58 | if let f = fromVC as? ScreenSelectorPreviewable where isReverse {
59 | containerView.insertSubview(toView, belowSubview: fromView)
60 | moveFromView = f.backgroundImageView
61 | copiedImageView = generateCopyOfImageView(moveFromView as? UIImageView)
62 | moveToView = moveFromImageView
63 | } else if let t = toVC as? ScreenSelectorPreviewable where !isReverse {
64 | containerView.addSubview(toView)
65 | moveFromView = moveFromImageView
66 | copiedImageView = generateCopyOfImageView(moveFromView as? UIImageView)
67 | moveToView = t.backgroundImageView
68 | } else {
69 | fatalError()
70 | }
71 |
72 | if let moveToView = moveToView, copiedImageView = copiedImageView, moveFromImageView = moveFromImageView {
73 | containerView.addSubview(copiedImageView)
74 | let duration = transitionDuration(transitionContext)
75 | let toFrame: CGRect
76 | if isReverse {
77 | fromView.hidden = true
78 | toFrame = containerView.convertRect(moveFromImageView.frame, fromView: moveFromImageView.superview)
79 | } else {
80 | toView.alpha = 0
81 | toFrame = containerView.convertRect(moveToView.frame, fromView: moveToView.superview)
82 | }
83 |
84 | UIView.animateWithDuration(duration * 0.6, delay: 0, options: [.BeginFromCurrentState, .CurveEaseOut], animations: {
85 | copiedImageView.frame = toFrame
86 | }) { (finished) in
87 | if self.isReverse {
88 | fromView.hidden = false
89 | // 完了通知
90 | copiedImageView.removeFromSuperview()
91 | let isCancelled = transitionContext.transitionWasCancelled()
92 | transitionContext.completeTransition(!isCancelled)
93 | } else {
94 | containerView.insertSubview(toView, aboveSubview: copiedImageView)
95 | UIView.animateWithDuration(duration * 0.4, delay: 0, options: [.BeginFromCurrentState], animations: {
96 | toView.alpha = 1.0
97 | }) { (finished) in
98 | fromView.hidden = false
99 | // 完了通知
100 | copiedImageView.removeFromSuperview()
101 | let isCancelled = transitionContext.transitionWasCancelled()
102 | transitionContext.completeTransition(!isCancelled)
103 | }
104 | }
105 | }
106 | } else {
107 | let isCancelled = transitionContext.transitionWasCancelled()
108 | transitionContext.completeTransition(!isCancelled)
109 | }
110 |
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenSelectorView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorView.swift
3 | // ScreenSelector
4 | //
5 | // Created by Tomonori Ueno on 2016/07/20.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol ScreenSelectorViewDelegate: class {
12 | func screenSelectorViewDidTapScreenAtIndex(index: Int, previewView: ScreenPreviewViewProtocol)
13 | }
14 | public protocol ScreenSelectorViewDataSource: class {
15 | func numberOfScreens() -> Int
16 | func previewViewForScreenAtIndex(index: Int) -> ScreenPreviewViewProtocol
17 | }
18 |
19 | @IBDesignable
20 | public class ScreenSelectorView: UIView {
21 |
22 | @IBInspectable public var horizontalMargin: CGFloat = 20
23 | @IBInspectable public var previewVerticalOffset: CGFloat = 0
24 | @IBInspectable public var previewReflectionEnabled: Bool = false
25 |
26 | public let scrollView: UIScrollView = UIScrollView()
27 | public weak var delegate: ScreenSelectorViewDelegate?
28 | public weak var dataSource: ScreenSelectorViewDataSource? {
29 | didSet {
30 | reloadData()
31 | }
32 | }
33 | public weak var scrollViewDelegate: UIScrollViewDelegate? {
34 | didSet {
35 | scrollView.delegate = scrollViewDelegate
36 | }
37 | }
38 | private var previewViews: [ScreenPreviewViewProtocol] = []
39 |
40 | required public init?(coder aDecoder: NSCoder) {
41 | super.init(coder: aDecoder)
42 | }
43 |
44 | public override init(frame: CGRect) {
45 | super.init(frame: frame)
46 | commonInit()
47 | }
48 |
49 | public override func prepareForInterfaceBuilder() {
50 | super.prepareForInterfaceBuilder()
51 | commonInit()
52 | scrollView.frame = bounds
53 | reloadData(dataSource: DummyScreenDataSource())
54 | }
55 |
56 | public override func awakeFromNib() {
57 | super.awakeFromNib()
58 | commonInit()
59 | }
60 |
61 | public override func didMoveToSuperview() {
62 | super.didMoveToSuperview()
63 | }
64 |
65 | public override func layoutSubviews() {
66 | super.layoutSubviews()
67 | scrollView.frame = bounds
68 | setScrollViewHorizontalInset()
69 | }
70 |
71 | private func commonInit() {
72 | setupScrollView()
73 | let tapRecog = UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
74 | addGestureRecognizer(tapRecog)
75 | scrollView.delegate = scrollViewDelegate
76 | scrollView.frame = bounds
77 | }
78 |
79 | private func setupScrollView() {
80 | scrollView.alwaysBounceHorizontal = true
81 | scrollView.showsVerticalScrollIndicator = false
82 | scrollView.showsHorizontalScrollIndicator = false
83 | addSubview(scrollView)
84 | }
85 |
86 | private func reloadData(dataSource dataSource: ScreenSelectorViewDataSource?) {
87 | guard let dataSource = dataSource where dataSource.numberOfScreens() > 0 else {
88 | return
89 | }
90 | removeAllPreviews()
91 | for i in 0.stride(to: dataSource.numberOfScreens(), by: 1) {
92 | let contentView = dataSource.previewViewForScreenAtIndex(i)
93 | previewViews.append(contentView)
94 | guard let c = contentView as? UIView else {
95 | fatalError()
96 | }
97 | var contentViewFrame = c.frame
98 | contentViewFrame.origin.x = CGFloat(i) * (horizontalMargin + contentViewFrame.size.width)
99 | c.frame = contentViewFrame
100 | c.center = CGPoint(x: c.center.x, y: bounds.height * 0.5 + previewVerticalOffset)
101 | scrollView.addSubview(c)
102 | scrollView.contentSize = CGSize(width: contentViewFrame.maxX, height: 0)
103 | if previewReflectionEnabled {
104 | addSpecularReflectionLayerToView(c)
105 | }
106 | }
107 | setScrollViewHorizontalInset()
108 | }
109 |
110 | private func setScrollViewHorizontalInset() {
111 | // Calculate horizontal inset to place first screen to center.
112 | let contentViewBounds = previewViews
113 | .map() { view in
114 | return view as? UIView
115 | }
116 | .flatMap() { a in a }
117 | .first?.bounds ?? CGRect.zero
118 | let horizontalInset = scrollView.bounds.width * 0.5 - contentViewBounds.width * 0.5
119 | scrollView.contentInset.left = horizontalInset
120 | scrollView.contentInset.right = horizontalInset
121 | scrollView.setContentOffset(CGPoint(x: -scrollView.contentInset.left, y: 0), animated: false)
122 | }
123 |
124 | private func addSpecularReflectionLayerToView(view: UIView) {
125 | let layer = SpecularReflectionLayer(sourceView: view)
126 | view.layer.addSublayer(layer)
127 | }
128 |
129 | private func removeAllPreviews() {
130 | previewViews.forEach { (previewView) in
131 | if let view = previewView as? UIView {
132 | view.removeFromSuperview()
133 | }
134 | }
135 | previewViews.removeAll()
136 | }
137 |
138 | public func reloadData() {
139 | reloadData(dataSource: dataSource)
140 | }
141 |
142 | public func scrollToIndex(index: Int, animated: Bool) {
143 | guard previewViews.count > index else {
144 | return
145 | }
146 | if let preview = previewViews[index] as? UIView {
147 | let xOffset = -(scrollView.bounds.width * 0.5 - (preview.frame.maxX - preview.bounds.midX))
148 | scrollView.setContentOffset(CGPoint(x: xOffset, y: 0), animated: animated)
149 | }
150 | }
151 |
152 | func tapped(tapRecog: UITapGestureRecognizer) {
153 | let location = tapRecog.locationInView(self)
154 | let tappedView = previewViews
155 | .filter { (view) -> Bool in
156 | guard let view = view as? UIView else {
157 | return false
158 | }
159 | let rectInView = scrollView.convertRect(view.frame, toView: self)
160 | return rectInView.contains(location)
161 | }
162 | .first
163 | let index = previewViews
164 | .indexOf { (viewProtocol) -> Bool in
165 | return viewProtocol === tappedView
166 | }
167 | if let t = tappedView, index = index {
168 | self.delegate?.screenSelectorViewDidTapScreenAtIndex(index, previewView: t)
169 | }
170 | }
171 |
172 | }
173 |
--------------------------------------------------------------------------------
/ScreenSelector/ScreenSelectorViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorViewController.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/22.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class ScreenSelectorViewController: UIViewController, ScreenSelectorViewDelegate, ScreenSelectorViewDataSource, UIViewControllerTransitioningDelegate {
12 |
13 | public let screenSelectorView = ScreenSelectorView()
14 | public var previewableScreens: [ScreenSelectorPreviewable] = []
15 |
16 | weak var transitionFromPreviewImageView: UIImageView?
17 |
18 | override public func viewDidLoad() {
19 | super.viewDidLoad()
20 | screenSelectorView.frame = view.bounds
21 | screenSelectorView.delegate = self
22 | screenSelectorView.dataSource = self
23 | view.addSubview(screenSelectorView)
24 | }
25 |
26 | override public func viewDidLayoutSubviews() {
27 | super.viewDidLayoutSubviews()
28 | }
29 |
30 | // MARK: - ScreenSelectorViewDelegate
31 |
32 | public func screenSelectorViewDidTapScreenAtIndex(index: Int, previewView: ScreenPreviewViewProtocol) {
33 | transitionFromPreviewImageView = previewView.imageView
34 | if let viewController = previewableScreens[index] as? UIViewController {
35 | viewController.transitioningDelegate = self
36 | presentViewController(viewController, animated: true) {
37 | // Move selected preview to center of screen.
38 | self.screenSelectorView.scrollToIndex(index, animated: false)
39 | }
40 | }
41 | }
42 |
43 | // MARK: - ScreenSelectorViewDataSource
44 |
45 | public func numberOfScreens() -> Int {
46 | return previewableScreens.count
47 | }
48 |
49 | public func previewViewForScreenAtIndex(index: Int) -> ScreenPreviewViewProtocol {
50 | let size = CGSize(width: UIScreen.mainScreen().bounds.width * 0.6, height: UIScreen.mainScreen().bounds.height * 0.6)
51 | let screenView = ScreenPreviewView(frame: CGRect(origin: CGPoint.zero, size: size))
52 | let previewable = previewableScreens[index]
53 | let previewImage: UIImage? = previewable.thumbnailImage
54 | guard let vc = previewable as? UIViewController else {
55 | fatalError()
56 | }
57 | let titleText: String? = vc.title
58 | screenView.titleLabel.text = titleText
59 | screenView.imageView.image = previewImage
60 | return screenView
61 | }
62 |
63 | // MARK: -
64 |
65 | public func animationControllerForPresentedController(presented: UIViewController,
66 | presentingController presenting: UIViewController,
67 | sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
68 | let animator = ScreenSelectorTransitioningAnimator(isReverse: false, moveFromImageView: transitionFromPreviewImageView)
69 | return animator
70 | }
71 |
72 | public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
73 | let animator = ScreenSelectorTransitioningAnimator(isReverse: true, moveFromImageView: transitionFromPreviewImageView)
74 | return animator
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/ScreenSelector/SpecularReflectionLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpecularReflectionLayer.swift
3 | // ScreenSelectorExample
4 | //
5 | // Created by Tomonori Ueno on 2016/07/26.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final public class SpecularReflectionLayer: CALayer {
12 |
13 | init(sourceView: UIView, xAngle: Double = M_PI) {
14 | super.init()
15 | bounds = sourceView.bounds
16 | commonInit(sourceView: sourceView, xAngle: xAngle)
17 | }
18 |
19 | required public init?(coder aDecoder: NSCoder) {
20 | fatalError("init(coder:) has not been implemented")
21 | }
22 |
23 | private func commonInit(sourceView view: UIView, xAngle: Double) {
24 | let image = generateImageOfView(sourceView: view)
25 | contents = image.CGImage
26 | opacity = 1.0
27 | anchorPoint = CGPoint(x: 0.5, y: 1.0)
28 | position = CGPoint(x: bounds.width * 0.5, y: bounds.height + 20)
29 | actions = ["transform" : NSNull()]
30 | var perspective = CATransform3DIdentity
31 | perspective.m34 = 1 / bounds.height * 0.25
32 | transform = CATransform3DConcat(CATransform3DMakeRotation(CGFloat(xAngle), 1, 0, 0), perspective)
33 | let gradientLayer = generateGradientLayer()
34 | mask = gradientLayer
35 | gradientLayer.anchorPoint = anchorPoint
36 | gradientLayer.position = position
37 | }
38 |
39 | private func generateGradientLayer() -> CAGradientLayer {
40 | let gradientLayer = CAGradientLayer()
41 | gradientLayer.colors = [UIColor(red: 0, green: 0, blue: 0, alpha: 0.3).CGColor, UIColor.clearColor().CGColor]
42 | gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
43 | gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.75)
44 | gradientLayer.bounds = bounds
45 | return gradientLayer
46 | }
47 |
48 | private func generateImageOfView(sourceView view: UIView) -> UIImage {
49 | UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0)
50 | #if TARGET_INTERFACE_BUILDER
51 | if let context = UIGraphicsGetCurrentContext() {
52 | view.layer.renderInContext(context)
53 | }
54 | #else
55 | view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
56 | #endif
57 | let image = UIGraphicsGetImageFromCurrentImageContext()
58 | UIGraphicsEndImageContext()
59 | return image
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/ScreenSelectorTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ScreenSelectorTests/ScreenSelectorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreenSelectorTests.swift
3 | // ScreenSelectorTests
4 | //
5 | // Created by Tomonori on 2016/08/15.
6 | // Copyright © 2016年 Tomonori Ueno. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ScreenSelector
11 |
12 | class ScreenSelectorTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tueno/ScreenSelector/11eeacd66d52c4673e695cafacfe060f25cefc6e/preview.gif
--------------------------------------------------------------------------------