├── .gitignore
├── Assets
├── snapchat.gif
└── snapchat_checkbox.gif
├── LICENSE
├── README.md
└── SnapchatCheckbox
├── SnapchatCheckbox.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
└── SnapchatCheckbox
├── AppDelegate.swift
├── Assets.xcassets
└── AppIcon.appiconset
│ └── Contents.json
├── Base.lproj
├── LaunchScreen.storyboard
└── Main.storyboard
├── Info.plist
├── SnapchatCheckbox.swift
└── ViewController.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 | *.DS_Store
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | .build/
40 |
41 | # CocoaPods
42 | #
43 | # We recommend against adding the Pods directory to your .gitignore. However
44 | # you should judge for yourself, the pros and cons are mentioned at:
45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
46 | #
47 | # Pods/
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
62 |
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 |
--------------------------------------------------------------------------------
/Assets/snapchat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielinoa/SnapchatCheckbox/7430e40bf46769a2d0fbbe125fc68a25a7ffac22/Assets/snapchat.gif
--------------------------------------------------------------------------------
/Assets/snapchat_checkbox.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielinoa/SnapchatCheckbox/7430e40bf46769a2d0fbbe125fc68a25a7ffac22/Assets/snapchat_checkbox.gif
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Daniel Inoa
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 | # SnapchatCheckbox
2 |
3 | In Snapchat, after receiving and opening a snap, there is the option to replay a snap by holding down on the specified snap, which results in a small box being filled in a circular manner.
4 |
5 |
6 |
7 | This checkbox is inspired by that control/view.
8 |
9 |
10 |
11 | ## Compatibility
12 |
13 | * This project is written in Swift 3.0 and requires Xcode 8.0+ to build and run.
14 | * SnapchatCheckbox runs on iOS 10+.
15 |
16 | ## Contributors
17 |
18 | * [Daniel Inoa](https://twitter.com/danielinoa_)
19 |
20 | ## License
21 |
22 | SnapchatCheckbox is under the MIT License.
23 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 01CF112C1DEA911D0020155D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF112B1DEA911D0020155D /* AppDelegate.swift */; };
11 | 01CF112E1DEA911D0020155D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF112D1DEA911D0020155D /* ViewController.swift */; };
12 | 01CF11311DEA911D0020155D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01CF112F1DEA911D0020155D /* Main.storyboard */; };
13 | 01CF11331DEA911D0020155D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01CF11321DEA911D0020155D /* Assets.xcassets */; };
14 | 01CF11361DEA911D0020155D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01CF11341DEA911D0020155D /* LaunchScreen.storyboard */; };
15 | 01CF113E1DEA915B0020155D /* SnapchatCheckbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CF113D1DEA915B0020155D /* SnapchatCheckbox.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 01CF11281DEA911D0020155D /* SnapchatCheckbox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SnapchatCheckbox.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 01CF112B1DEA911D0020155D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | 01CF112D1DEA911D0020155D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
22 | 01CF11301DEA911D0020155D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
23 | 01CF11321DEA911D0020155D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
24 | 01CF11351DEA911D0020155D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
25 | 01CF11371DEA911D0020155D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | 01CF113D1DEA915B0020155D /* SnapchatCheckbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapchatCheckbox.swift; sourceTree = ""; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 01CF11251DEA911D0020155D /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | );
35 | runOnlyForDeploymentPostprocessing = 0;
36 | };
37 | /* End PBXFrameworksBuildPhase section */
38 |
39 | /* Begin PBXGroup section */
40 | 01CF111F1DEA911D0020155D = {
41 | isa = PBXGroup;
42 | children = (
43 | 01CF112A1DEA911D0020155D /* SnapchatCheckbox */,
44 | 01CF11291DEA911D0020155D /* Products */,
45 | );
46 | sourceTree = "";
47 | };
48 | 01CF11291DEA911D0020155D /* Products */ = {
49 | isa = PBXGroup;
50 | children = (
51 | 01CF11281DEA911D0020155D /* SnapchatCheckbox.app */,
52 | );
53 | name = Products;
54 | sourceTree = "";
55 | };
56 | 01CF112A1DEA911D0020155D /* SnapchatCheckbox */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 01CF112B1DEA911D0020155D /* AppDelegate.swift */,
60 | 01CF113D1DEA915B0020155D /* SnapchatCheckbox.swift */,
61 | 01CF112D1DEA911D0020155D /* ViewController.swift */,
62 | 01CF112F1DEA911D0020155D /* Main.storyboard */,
63 | 01CF11321DEA911D0020155D /* Assets.xcassets */,
64 | 01CF11341DEA911D0020155D /* LaunchScreen.storyboard */,
65 | 01CF11371DEA911D0020155D /* Info.plist */,
66 | );
67 | path = SnapchatCheckbox;
68 | sourceTree = "";
69 | };
70 | /* End PBXGroup section */
71 |
72 | /* Begin PBXNativeTarget section */
73 | 01CF11271DEA911D0020155D /* SnapchatCheckbox */ = {
74 | isa = PBXNativeTarget;
75 | buildConfigurationList = 01CF113A1DEA911D0020155D /* Build configuration list for PBXNativeTarget "SnapchatCheckbox" */;
76 | buildPhases = (
77 | 01CF11241DEA911D0020155D /* Sources */,
78 | 01CF11251DEA911D0020155D /* Frameworks */,
79 | 01CF11261DEA911D0020155D /* Resources */,
80 | );
81 | buildRules = (
82 | );
83 | dependencies = (
84 | );
85 | name = SnapchatCheckbox;
86 | productName = SnapchatCheckbox;
87 | productReference = 01CF11281DEA911D0020155D /* SnapchatCheckbox.app */;
88 | productType = "com.apple.product-type.application";
89 | };
90 | /* End PBXNativeTarget section */
91 |
92 | /* Begin PBXProject section */
93 | 01CF11201DEA911D0020155D /* Project object */ = {
94 | isa = PBXProject;
95 | attributes = {
96 | LastSwiftUpdateCheck = 0810;
97 | LastUpgradeCheck = 0810;
98 | ORGANIZATIONNAME = "Daniel Inoa";
99 | TargetAttributes = {
100 | 01CF11271DEA911D0020155D = {
101 | CreatedOnToolsVersion = 8.1;
102 | DevelopmentTeam = A8SJS26GGQ;
103 | ProvisioningStyle = Automatic;
104 | };
105 | };
106 | };
107 | buildConfigurationList = 01CF11231DEA911D0020155D /* Build configuration list for PBXProject "SnapchatCheckbox" */;
108 | compatibilityVersion = "Xcode 3.2";
109 | developmentRegion = English;
110 | hasScannedForEncodings = 0;
111 | knownRegions = (
112 | en,
113 | Base,
114 | );
115 | mainGroup = 01CF111F1DEA911D0020155D;
116 | productRefGroup = 01CF11291DEA911D0020155D /* Products */;
117 | projectDirPath = "";
118 | projectRoot = "";
119 | targets = (
120 | 01CF11271DEA911D0020155D /* SnapchatCheckbox */,
121 | );
122 | };
123 | /* End PBXProject section */
124 |
125 | /* Begin PBXResourcesBuildPhase section */
126 | 01CF11261DEA911D0020155D /* Resources */ = {
127 | isa = PBXResourcesBuildPhase;
128 | buildActionMask = 2147483647;
129 | files = (
130 | 01CF11361DEA911D0020155D /* LaunchScreen.storyboard in Resources */,
131 | 01CF11331DEA911D0020155D /* Assets.xcassets in Resources */,
132 | 01CF11311DEA911D0020155D /* Main.storyboard in Resources */,
133 | );
134 | runOnlyForDeploymentPostprocessing = 0;
135 | };
136 | /* End PBXResourcesBuildPhase section */
137 |
138 | /* Begin PBXSourcesBuildPhase section */
139 | 01CF11241DEA911D0020155D /* Sources */ = {
140 | isa = PBXSourcesBuildPhase;
141 | buildActionMask = 2147483647;
142 | files = (
143 | 01CF112E1DEA911D0020155D /* ViewController.swift in Sources */,
144 | 01CF112C1DEA911D0020155D /* AppDelegate.swift in Sources */,
145 | 01CF113E1DEA915B0020155D /* SnapchatCheckbox.swift in Sources */,
146 | );
147 | runOnlyForDeploymentPostprocessing = 0;
148 | };
149 | /* End PBXSourcesBuildPhase section */
150 |
151 | /* Begin PBXVariantGroup section */
152 | 01CF112F1DEA911D0020155D /* Main.storyboard */ = {
153 | isa = PBXVariantGroup;
154 | children = (
155 | 01CF11301DEA911D0020155D /* Base */,
156 | );
157 | name = Main.storyboard;
158 | sourceTree = "";
159 | };
160 | 01CF11341DEA911D0020155D /* LaunchScreen.storyboard */ = {
161 | isa = PBXVariantGroup;
162 | children = (
163 | 01CF11351DEA911D0020155D /* Base */,
164 | );
165 | name = LaunchScreen.storyboard;
166 | sourceTree = "";
167 | };
168 | /* End PBXVariantGroup section */
169 |
170 | /* Begin XCBuildConfiguration section */
171 | 01CF11381DEA911D0020155D /* Debug */ = {
172 | isa = XCBuildConfiguration;
173 | buildSettings = {
174 | ALWAYS_SEARCH_USER_PATHS = NO;
175 | CLANG_ANALYZER_NONNULL = YES;
176 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
177 | CLANG_CXX_LIBRARY = "libc++";
178 | CLANG_ENABLE_MODULES = YES;
179 | CLANG_ENABLE_OBJC_ARC = YES;
180 | CLANG_WARN_BOOL_CONVERSION = YES;
181 | CLANG_WARN_CONSTANT_CONVERSION = YES;
182 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
183 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
184 | CLANG_WARN_EMPTY_BODY = YES;
185 | CLANG_WARN_ENUM_CONVERSION = YES;
186 | CLANG_WARN_INFINITE_RECURSION = YES;
187 | CLANG_WARN_INT_CONVERSION = YES;
188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
189 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
190 | CLANG_WARN_UNREACHABLE_CODE = YES;
191 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
192 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
193 | COPY_PHASE_STRIP = NO;
194 | DEBUG_INFORMATION_FORMAT = dwarf;
195 | ENABLE_STRICT_OBJC_MSGSEND = YES;
196 | ENABLE_TESTABILITY = YES;
197 | GCC_C_LANGUAGE_STANDARD = gnu99;
198 | GCC_DYNAMIC_NO_PIC = NO;
199 | GCC_NO_COMMON_BLOCKS = YES;
200 | GCC_OPTIMIZATION_LEVEL = 0;
201 | GCC_PREPROCESSOR_DEFINITIONS = (
202 | "DEBUG=1",
203 | "$(inherited)",
204 | );
205 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
206 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
207 | GCC_WARN_UNDECLARED_SELECTOR = YES;
208 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
209 | GCC_WARN_UNUSED_FUNCTION = YES;
210 | GCC_WARN_UNUSED_VARIABLE = YES;
211 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
212 | MTL_ENABLE_DEBUG_INFO = YES;
213 | ONLY_ACTIVE_ARCH = YES;
214 | SDKROOT = iphoneos;
215 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
216 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
217 | };
218 | name = Debug;
219 | };
220 | 01CF11391DEA911D0020155D /* Release */ = {
221 | isa = XCBuildConfiguration;
222 | buildSettings = {
223 | ALWAYS_SEARCH_USER_PATHS = NO;
224 | CLANG_ANALYZER_NONNULL = YES;
225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
226 | CLANG_CXX_LIBRARY = "libc++";
227 | CLANG_ENABLE_MODULES = YES;
228 | CLANG_ENABLE_OBJC_ARC = YES;
229 | CLANG_WARN_BOOL_CONVERSION = YES;
230 | CLANG_WARN_CONSTANT_CONVERSION = YES;
231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
232 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
233 | CLANG_WARN_EMPTY_BODY = YES;
234 | CLANG_WARN_ENUM_CONVERSION = YES;
235 | CLANG_WARN_INFINITE_RECURSION = YES;
236 | CLANG_WARN_INT_CONVERSION = YES;
237 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
238 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
239 | CLANG_WARN_UNREACHABLE_CODE = YES;
240 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
241 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
242 | COPY_PHASE_STRIP = NO;
243 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
244 | ENABLE_NS_ASSERTIONS = NO;
245 | ENABLE_STRICT_OBJC_MSGSEND = YES;
246 | GCC_C_LANGUAGE_STANDARD = gnu99;
247 | GCC_NO_COMMON_BLOCKS = YES;
248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
250 | GCC_WARN_UNDECLARED_SELECTOR = YES;
251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
252 | GCC_WARN_UNUSED_FUNCTION = YES;
253 | GCC_WARN_UNUSED_VARIABLE = YES;
254 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
255 | MTL_ENABLE_DEBUG_INFO = NO;
256 | SDKROOT = iphoneos;
257 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
258 | VALIDATE_PRODUCT = YES;
259 | };
260 | name = Release;
261 | };
262 | 01CF113B1DEA911D0020155D /* Debug */ = {
263 | isa = XCBuildConfiguration;
264 | buildSettings = {
265 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
266 | DEVELOPMENT_TEAM = A8SJS26GGQ;
267 | INFOPLIST_FILE = SnapchatCheckbox/Info.plist;
268 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
269 | PRODUCT_BUNDLE_IDENTIFIER = com.danielinoa.SnapchatCheckbox;
270 | PRODUCT_NAME = "$(TARGET_NAME)";
271 | SWIFT_VERSION = 3.0;
272 | };
273 | name = Debug;
274 | };
275 | 01CF113C1DEA911D0020155D /* Release */ = {
276 | isa = XCBuildConfiguration;
277 | buildSettings = {
278 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
279 | DEVELOPMENT_TEAM = A8SJS26GGQ;
280 | INFOPLIST_FILE = SnapchatCheckbox/Info.plist;
281 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
282 | PRODUCT_BUNDLE_IDENTIFIER = com.danielinoa.SnapchatCheckbox;
283 | PRODUCT_NAME = "$(TARGET_NAME)";
284 | SWIFT_VERSION = 3.0;
285 | };
286 | name = Release;
287 | };
288 | /* End XCBuildConfiguration section */
289 |
290 | /* Begin XCConfigurationList section */
291 | 01CF11231DEA911D0020155D /* Build configuration list for PBXProject "SnapchatCheckbox" */ = {
292 | isa = XCConfigurationList;
293 | buildConfigurations = (
294 | 01CF11381DEA911D0020155D /* Debug */,
295 | 01CF11391DEA911D0020155D /* Release */,
296 | );
297 | defaultConfigurationIsVisible = 0;
298 | defaultConfigurationName = Release;
299 | };
300 | 01CF113A1DEA911D0020155D /* Build configuration list for PBXNativeTarget "SnapchatCheckbox" */ = {
301 | isa = XCConfigurationList;
302 | buildConfigurations = (
303 | 01CF113B1DEA911D0020155D /* Debug */,
304 | 01CF113C1DEA911D0020155D /* Release */,
305 | );
306 | defaultConfigurationIsVisible = 0;
307 | };
308 | /* End XCConfigurationList section */
309 | };
310 | rootObject = 01CF11201DEA911D0020155D /* Project object */;
311 | }
312 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SnapchatCheckbox
4 | //
5 | // Created by Daniel Inoa on 11/26/16.
6 | // Copyright © 2016 Daniel Inoa. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
17 | return true
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/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 | }
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/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 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/Base.lproj/Main.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 |
29 |
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 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/SnapchatCheckbox.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Daniel Inoa on 11/19/16.
3 | // Copyright © 2016 Daniel Inoa. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | @IBDesignable final class SnapchatCheckbox: UIControl {
9 |
10 | private(set) var isChecked: Bool = false
11 |
12 | func setChecked(_ checked: Bool, animated: Bool = false) {
13 | let fromValue: Float = isChecked ? 1 : 0
14 | let toValue: Float = isChecked ? 0 : 1
15 | if animated {
16 | let animation = CAKeyframeAnimation(keyPath: "path")
17 | let byValue: Float = 0.01 * ( !isChecked ? 1 : -1)
18 | let pathValues = stride(from: fromValue, to: toValue, by: byValue).map({ piePath(withFraction: $0).cgPath })
19 | animation.values = pathValues
20 | animation.duration = 0.5
21 | shapeLayer.add(animation, forKey: "pathAnimation")
22 | }
23 | shapeLayer.path = piePath(withFraction: toValue).cgPath
24 | isChecked = checked
25 | }
26 |
27 | // MARK: - Lifecycle
28 |
29 | override init(frame: CGRect) {
30 | super.init(frame: frame)
31 | configure()
32 | }
33 |
34 | required init?(coder aDecoder: NSCoder) {
35 | super.init(coder: aDecoder)
36 | configure()
37 | }
38 |
39 | private func configure() {
40 | clipsToBounds = true
41 | layer.cornerRadius = 5
42 | layer.borderColor = tintColor.cgColor
43 | layer.borderWidth = 4
44 | layer.addSublayer(shapeLayer)
45 | }
46 |
47 | // MARK: - Appearance
48 |
49 | override var isHighlighted: Bool {
50 | didSet {
51 | backgroundColor = isHighlighted ? tintColor.withAlphaComponent(0.2) : .clear
52 | }
53 | }
54 |
55 | override var clipsToBounds: Bool {
56 | didSet {
57 | // workaround
58 | if !clipsToBounds {
59 | clipsToBounds = true
60 | }
61 | }
62 | }
63 |
64 | private lazy var shapeLayer: CAShapeLayer = {
65 | let layer = CAShapeLayer()
66 | layer.fillColor = self.tintColor.cgColor
67 | let fraction: Float = self.isChecked ? 1 : 0
68 | layer.path = self.piePath(withFraction: fraction).cgPath
69 | return layer
70 | }()
71 |
72 | private func piePath(withFraction fraction: Float) -> UIBezierPath {
73 | let fraction = min(max(0, fraction), 1)
74 | let center = CGPoint(x: bounds.width/2, y: bounds.height/2)
75 | let radius = max(bounds.width, bounds.height)
76 | let path = UIBezierPath()
77 | path.move(to: center)
78 | path.addArc(withCenter: center,
79 | radius: radius,
80 | startAngle: -CGFloat(M_PI_2),
81 | endAngle: -CGFloat(M_PI * 2) * CGFloat(fraction) - CGFloat(M_PI_2),
82 | clockwise: false)
83 | path.addLine(to: center)
84 | return path
85 | }
86 |
87 | // MARK: - Auto Layout
88 |
89 | override var intrinsicContentSize: CGSize {
90 | return CGSize(width: 40, height: 40)
91 | }
92 |
93 | // MARK: - Tracking
94 |
95 | override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
96 | super.endTracking(touch, with: event)
97 | if let touchLocation = touch?.location(in: self), bounds.contains(touchLocation) {
98 | setChecked(!isChecked, animated: true)
99 | sendActions(for: .valueChanged)
100 | }
101 | }
102 |
103 | // MARK: - Interface Builder
104 |
105 | override func prepareForInterfaceBuilder() {
106 | super.prepareForInterfaceBuilder()
107 | setNeedsDisplay()
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/SnapchatCheckbox/SnapchatCheckbox/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SnapchatCheckbox
4 | //
5 | // Created by Daniel Inoa on 11/26/16.
6 | // Copyright © 2016 Daniel Inoa. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var checkbox: SnapchatCheckbox!
14 | @IBOutlet weak var isCheckedLabel: UILabel!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | isCheckedLabel.text = checkbox.isChecked ? "checked" : "unchecked"
19 | }
20 |
21 | @IBAction func checkboxTapped(_ sender: Any) {
22 | isCheckedLabel.text = checkbox.isChecked ? "checked" : "unchecked"
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------