├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── Carthage
└── Build
│ ├── .Switches.version
│ └── iOS
│ ├── 7C963147-D6EB-33ED-821F-9125EE2671FC.bcsymbolmap
│ ├── Switches.framework.dSYM
│ └── Contents
│ │ ├── Info.plist
│ │ └── Resources
│ │ └── DWARF
│ │ └── Switches
│ └── Switches.framework
│ ├── Headers
│ ├── Switches-Swift.h
│ └── Switches.h
│ ├── Info.plist
│ ├── Modules
│ ├── Switches.swiftmodule
│ │ ├── Project
│ │ │ ├── x86_64-apple-ios-simulator.swiftsourceinfo
│ │ │ └── x86_64.swiftsourceinfo
│ │ ├── arm64-apple-ios.swiftdoc
│ │ ├── arm64-apple-ios.swiftmodule
│ │ ├── arm64.swiftdoc
│ │ ├── arm64.swiftmodule
│ │ ├── x86_64-apple-ios-simulator.swiftdoc
│ │ ├── x86_64-apple-ios-simulator.swiftmodule
│ │ ├── x86_64.swiftdoc
│ │ └── x86_64.swiftmodule
│ └── module.modulemap
│ └── Switches
├── LICENSE
├── Package.swift
├── README.md
├── Sources
├── Info.plist
├── Switches.h
├── Switches.swift
└── Switches
│ ├── BaseControl.swift
│ ├── Extensions
│ ├── CALayer+Extension.swift
│ ├── CGRect+Extension.swift
│ └── UIImage+Extension.swift
│ ├── JDSwitch.swift
│ ├── SDSwitch.swift
│ ├── Switcher.swift
│ ├── YapBaseSwitch.swift
│ ├── YapLiquidSwitch.swift
│ ├── YapSmileSwitch.swift
│ └── YapSwitch.swift
├── Switches.podspec
├── Switches.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── Switches.xcscheme
│ │ └── SwitchesDemo.xcscheme
└── xcuserdata
│ └── jawadali.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── SwitchesDemo
├── Application
│ ├── AppDelegate.swift
│ └── SceneDelegate.swift
├── Controllers
│ ├── AnimatedSwitchesViewController.swift
│ ├── CollectionViewCell
│ │ └── CollectionViewCell.swift
│ ├── GradientSwitchesViewController.swift
│ ├── JellySwitchesViewController.swift
│ ├── LoadingSwitchesViewController.swift
│ ├── ModeBSwitchesViewController.swift
│ ├── ModeSwitchesViewController.swift
│ ├── RandomViewController.swift
│ ├── SmileyViewController.swift
│ ├── SwiftyViewController.swift
│ ├── ThumbImageSwitchesViewController.swift
│ └── ViewController.swift
├── Model
│ └── SwitchType.swift
├── Resources
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── ItunesArtwork@2x.png
│ │ ├── Contents.json
│ │ ├── check.imageset
│ │ │ ├── Contents.json
│ │ │ └── check@3x.png
│ │ ├── check1.imageset
│ │ │ ├── Contents.json
│ │ │ └── check1.png
│ │ ├── check9.imageset
│ │ │ ├── Contents.json
│ │ │ └── check9.png
│ │ ├── close.imageset
│ │ │ ├── Contents.json
│ │ │ └── close.pdf
│ │ ├── cross1.imageset
│ │ │ ├── Contents.json
│ │ │ └── cross1.png
│ │ ├── cross24.imageset
│ │ │ ├── Contents.json
│ │ │ └── cross24.png
│ │ ├── cross7.imageset
│ │ │ ├── Contents.json
│ │ │ └── cross7.png
│ │ ├── go1.imageset
│ │ │ ├── Contents.json
│ │ │ └── go1.png
│ │ ├── go2.imageset
│ │ │ ├── Contents.json
│ │ │ └── go2.png
│ │ ├── icon_check_primary_dark.imageset
│ │ │ ├── Contents.json
│ │ │ └── icon_check_primary_dark.pdf
│ │ ├── icon_close_dark_purple.imageset
│ │ │ ├── Contents.json
│ │ │ └── icon_close_dark_purple.pdf
│ │ ├── left.imageset
│ │ │ ├── Contents.json
│ │ │ └── left.png
│ │ ├── off1.imageset
│ │ │ ├── Contents.json
│ │ │ └── off1.png
│ │ ├── off2.imageset
│ │ │ ├── Contents.json
│ │ │ └── off2.png
│ │ ├── onTick.imageset
│ │ │ ├── Contents.json
│ │ │ └── onTick.png
│ │ ├── q1.imageset
│ │ │ ├── Contents.json
│ │ │ └── q1.png
│ │ ├── right.imageset
│ │ │ ├── Contents.json
│ │ │ └── right.png
│ │ ├── switch-animation-post.imageset
│ │ │ ├── Contents.json
│ │ │ └── switch-animation-post.jpg
│ │ ├── thumb.imageset
│ │ │ ├── Contents.json
│ │ │ └── thumb.png
│ │ ├── thumb1.imageset
│ │ │ ├── Contents.json
│ │ │ └── thumb1.png
│ │ ├── thumb12.imageset
│ │ │ ├── Contents.json
│ │ │ └── thumb12.png
│ │ ├── thumb4.imageset
│ │ │ ├── Contents.json
│ │ │ └── thumb4.png
│ │ ├── thumb7.imageset
│ │ │ ├── Contents.json
│ │ │ └── thumb7.png
│ │ └── w1.imageset
│ │ │ ├── Contents.json
│ │ │ └── w1.png
│ └── Info.plist
└── Storyboard
│ └── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── SwitchesDemoTests
├── Info.plist
└── SwitchesDemoTests.swift
├── SwitchesDemoUITests
├── Info.plist
└── SwitchesDemoUITests.swift
└── images
├── Screen Recording 2020-08-31 at 3.39.54 PM.gif
├── abcd
├── ezgif.com-video-to-gif-23.gif
├── ezgif.com-video-to-gif-24.gif
├── ezgif.com-video-to-gif-25.gif
└── ezgif.com-video-to-gif-26.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Carthage/Build/.Switches.version:
--------------------------------------------------------------------------------
1 | {
2 | "Mac" : [
3 |
4 | ],
5 | "watchOS" : [
6 |
7 | ],
8 | "tvOS" : [
9 |
10 | ],
11 | "commitish" : "1.0.2",
12 | "iOS" : [
13 | {
14 | "name" : "Switches",
15 | "hash" : "76e27d2ac2a328b3a1a6e2fc99ff1d6159a11e85e9f2f1921ce415617b0fda32",
16 | "swiftToolchainVersion" : "5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)"
17 | }
18 | ]
19 | }
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework.dSYM/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleIdentifier
8 | com.apple.xcode.dsym.XeroT.Switches
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundlePackageType
12 | dSYM
13 | CFBundleSignature
14 | ????
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleVersion
18 | 1
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework.dSYM/Contents/Resources/DWARF/Switches:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework.dSYM/Contents/Resources/DWARF/Switches
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Headers/Switches.h:
--------------------------------------------------------------------------------
1 | //
2 | // Switches.h
3 | // Switches
4 | //
5 | // Created by Jawad Ali on 30/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for Switches.
12 | FOUNDATION_EXPORT double SwitchesVersionNumber;
13 |
14 | //! Project version string for Switches.
15 | FOUNDATION_EXPORT const unsigned char SwitchesVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Info.plist
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/Project/x86_64.swiftsourceinfo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/Project/x86_64.swiftsourceinfo
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64-apple-ios.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64-apple-ios.swiftdoc
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64-apple-ios.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64-apple-ios.swiftmodule
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64.swiftdoc
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/arm64.swiftmodule
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64-apple-ios-simulator.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64-apple-ios-simulator.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64-apple-ios-simulator.swiftmodule
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64.swiftdoc
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Modules/Switches.swiftmodule/x86_64.swiftmodule
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module Switches {
2 | umbrella header "Switches.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
8 | module Switches.Swift {
9 | header "Switches-Swift.h"
10 | requires objc
11 | }
12 |
--------------------------------------------------------------------------------
/Carthage/Build/iOS/Switches.framework/Switches:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/Carthage/Build/iOS/Switches.framework/Switches
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Jawad Ali
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 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Switches",
8 | platforms: [
9 | .iOS(.v11),
10 | ],
11 | products: [
12 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
13 | .library(
14 | name: "Switches",
15 | targets: ["Switches"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
24 | .target(
25 | name: "Switches",
26 | dependencies: []),
27 | .testTarget(
28 | name: "SwitchesTests",
29 | dependencies: ["Switches"]),
30 | ]
31 | )
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # Switches Animations
7 | > An animated switch collection
8 |
9 |
10 | [](https://travis-ci.org/jwd-ali/RingPieChart)
11 | [](https://github.com/Carthage/Carthage)
12 | [](https://swift.org)
13 |
14 | Add Beautiful Customise Switch in your application to enhance your application UI and UX
15 |
16 | ___
17 |
18 | # Medium Article:
19 | > https://medium.com/@l060214/how-to-create-loading-uiswitch-with-calayers-and-caanimations-4667c1fa845
20 |
21 | ___
22 |
23 |
24 | From time to time I browse Dribbble to get inspiration from UI/UX designers. You often see non-native control elements in these designs. Some, such as checkboxes, have no native counterpart in UIKit while others like switches are— except they’re nearly impossible to customize. You cannot even change the size of a UISwitch. What if you need to implement a completely custom designed switch for your app like this one
25 |
26 |
27 | If you wanted to implement any of these designs it would be a poor choice to subclass `UISwitch` as you can hardly customize the colours — aside from the on/off tint.
28 | So I thought I would try to re-engineer the UISwitch so that I would have complete control over each aspect, making it easy to style in the future.Turns out its actually pretty easy (and a lot of fun!) to build these control elements from scratch. I even went so far as to add the ability to set on/off text or images. For those who don’t know, UISwitch has onImage and offImage which when set don’t do anything anymore.
29 |
30 | So i take few of the Dribble switches Daily UI challenges as challenge and implemented them in this library.This library has cool and sophisticated animations,Designs and effects. Also, customizable properties can be tweaked behaviors and enhance your application UI cool. With this library, you can easily implement material design switch to your app.
31 |
32 |
33 | > You can play with the attributes and can customise them according to your UI demands. Below are the few examples
34 | ## Usage example
35 |
36 | |Class|Example|
37 | |-| -------- |
38 | |Switcher|
Dribble UI Challenge: https://dribbble.com/shots/4148855-Switcher-XXXIII|
39 | |SwitcherFullStrtech|
Dribble UI Challenge:https://dribbble.com/shots/3844909-On-Off|
40 | |SDSwitch|
Dribble UI Challenge:https://dribbble.com/shots/3545882-Switch-with-server-calls|
41 | |YapDarkAndLightModeSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2484722-Daily-Ui-Day-15-On-Off-Switch|
42 | |YapAnimatedSwitch|
Dribble UI Challenge:https://dribbble.com/shots/2309834-Yet-another-toggle-animation|
43 | |SDSwitch |
Dribble UI Challenge:https://dribbble.com/shots/5192899-Simple-toggle|
44 | |YapFullTextSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2330566-Morph-Switch|
45 | |JDSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2346044-Switch-on-off|
46 | |YapSmileSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2011284-Switcher-ll|
47 | |YapLiquidSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2028065-Switcher-lll|
48 | |YapSwitchSlim |
Dribble UI Challenge:https://dribbble.com/shots/2158763-simple-toggle|
49 | |YapGradientSwitch |
Dribble UI Challenge:https://dribbble.com/shots/2603107-toggle-switch-micro-interaction|
50 | |YapHalfStretchSwitch |
|
51 | |YapSwitch |
|
52 | |YapFullStretchSwitch |
|
53 | |YapSwitch |
|
54 |
55 | ## Requirements
56 |
57 | - iOS 10.0+ / Mac OS X 10.9+ / watchOS 2.0+ / tvOS 9.0+
58 | - Xcode 8.0+
59 |
60 | ## Installation
61 |
62 | ### [CocoaPods](http://cocoapods.org)
63 |
64 | To integrate **Switches Animations** into your Xcode project using CocoaPods, specify it in your `Podfile`:
65 |
66 | ```ruby
67 | use_frameworks!
68 |
69 | pod 'Switches'
70 | ```
71 |
72 | Then, run the following command:
73 |
74 | ```bash
75 | $ pod install
76 | ```
77 |
78 | ### [Swift Package Manager (SPM)](https://swift.org/package-manager)
79 |
80 | #### Prerequisites
81 | - OSX
82 |
83 |
84 | #### Update `Package.swift`
85 | To integrate `Switches Animations` in your project, add the proper description to your `Package.swift` file:
86 | ```swift
87 | // swift-tools-version:5.0
88 | import PackageDescription
89 |
90 | let package = Package(
91 | name: "YOUR_PROJECT_NAME",
92 | dependencies: [
93 | .package(url: "https://github.com/jwd-ali/Switch-Animations.git")
94 | ],
95 | targets: [
96 | .target(
97 | name: "YOUR_TARGET_NAME",
98 | dependencies: ["Switch-Animations"]
99 | ),
100 | ...
101 | ]
102 | )
103 | ```
104 |
105 |
106 | ### [Carthage](http://github.com/Carthage/Carthage)
107 |
108 | To integrate `Switches Animations` into your Xcode project using Carthage, specify it in your `Cartfile`:
109 |
110 | ```ogdl
111 | github "jwd-ali/Switch-Animations"
112 | ```
113 | ### Manually
114 |
115 | If you prefer not to use a dependency manager, you can integrate Switches Animations into your project manually.
116 |
117 | - Add Sources folder into your project
118 |
119 | ## Integration
120 | See the Demo Xcode project its easy to understand with proper comments on properties .. write me if you didn't get anything L060214@gmail.com
121 |
122 | Be careful!!!
123 | Irreversible consequences are possible during long work with the framework.
124 |
125 |
126 |
127 |
128 |
129 | ## Contributing
130 |
131 | I’d love to have help on this project. For small changes please [open a pull request](https://github.com/jwd-ali/Switch-Animations/pulls), for larger changes please [open an issue](https://github.com/jwd-ali/Switch-Animations/issues) first to discuss what you’d like to see.
132 |
133 |
134 | License
135 | -------
136 |
137 | Switch-Animations is under [MIT](https://opensource.org/licenses/MIT). See [LICENSE](LICENSE) file for more info.
138 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sources/Switches.h:
--------------------------------------------------------------------------------
1 | //
2 | // Switches.h
3 | // Switches
4 | //
5 | // Created by Jawad Ali on 30/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for Switches.
12 | FOUNDATION_EXPORT double SwitchesVersionNumber;
13 |
14 | //! Project version string for Switches.
15 | FOUNDATION_EXPORT const unsigned char SwitchesVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Sources/Switches.swift:
--------------------------------------------------------------------------------
1 | struct Switches {
2 | var text = "Hello, World!"
3 | }
4 |
--------------------------------------------------------------------------------
/Sources/Switches/BaseControl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseControl.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 28/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public typealias SDSwitchValueChange = (_ value: Bool) -> Void
12 | open class BaseControl: UIControl {
13 | // MARK: - Property
14 |
15 | open var valueChange: SDSwitchValueChange?
16 |
17 | open var isOn: Bool = false
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/Switches/Extensions/CALayer+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+Extension.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 20/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | public extension CALayer {
11 | var areAnimationsEnabled: Bool {
12 | get { delegate == nil }
13 | set { delegate = newValue ? nil : CALayerAnimationsDisablingDelegate.shared }
14 | }
15 |
16 | private class CALayerAnimationsDisablingDelegate: NSObject, CALayerDelegate {
17 | static let shared = CALayerAnimationsDisablingDelegate()
18 | private let null = NSNull()
19 |
20 | func action(for layer: CALayer, forKey event: String) -> CAAction? {
21 | self.null
22 | }
23 | }
24 |
25 | func bringToFront() {
26 | guard let sLayer = superlayer else {
27 | return
28 | }
29 | removeFromSuperlayer()
30 | sLayer.insertSublayer(self, at: UInt32(sLayer.sublayers?.count ?? 0))
31 | }
32 |
33 | func sendToBack() {
34 | guard let sLayer = superlayer else {
35 | return
36 | }
37 | removeFromSuperlayer()
38 | sLayer.insertSublayer(self, at: 0)
39 | }
40 |
41 | func animateGradientColors(from: [CGColor], to: [CGColor], duration: Double) {
42 | let animation = CABasicAnimation(keyPath: "colors")
43 | animation.fromValue = from
44 | animation.toValue = to
45 | animation.duration = duration
46 | animation.fillMode = .forwards
47 | animation.isRemovedOnCompletion = false
48 |
49 | // add the animation to the gradient
50 | self.add(animation, forKey: nil)
51 | }
52 |
53 | func strokeAnimation(duration: Double) {
54 | let animation = CABasicAnimation(keyPath: "strokeEnd")
55 | animation.fromValue = 0
56 | animation.toValue = 1
57 | animation.duration = duration
58 | animation.fillMode = .forwards
59 | animation.isRemovedOnCompletion = false
60 | self.add(animation, forKey: "line")
61 | }
62 |
63 | func rotateAnimation(angal: CGFloat, duration: Double, repeatAnimation: Bool = false) {
64 | let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
65 | rotationAnimation.fromValue = 0
66 | rotationAnimation.toValue = angal
67 | rotationAnimation.duration = duration
68 | rotationAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
69 | rotationAnimation.fillMode = .forwards
70 | rotationAnimation.isRemovedOnCompletion = false
71 | rotationAnimation.repeatCount = repeatAnimation ? .infinity : 0
72 | self.add(rotationAnimation, forKey: "rotation")
73 | }
74 |
75 | func removeRotationAnimation() {
76 | self.removeAnimation(forKey: "rotation")
77 | }
78 |
79 | func animateShape(path: CGPath, duration: Double) {
80 | let animation = CABasicAnimation(keyPath: "path")
81 | animation.duration = duration
82 | animation.toValue = path
83 | animation.timingFunction = CAMediaTimingFunction(name: .linear)
84 | animation.isRemovedOnCompletion = false
85 | animation.fillMode = .forwards
86 |
87 | self.add(animation, forKey: nil)
88 | }
89 |
90 | func doMask(by imageMask: UIImage) {
91 | let maskLayer = CAShapeLayer()
92 | maskLayer.bounds = CGRect(x: 0, y: 0, width: imageMask.size.width, height: imageMask.size.height)
93 | bounds = maskLayer.bounds
94 | maskLayer.contents = imageMask.cgImage
95 | maskLayer.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
96 | mask = maskLayer
97 | }
98 |
99 | func toImage() -> UIImage? {
100 | UIGraphicsBeginImageContextWithOptions(bounds.size,
101 | isOpaque,
102 | UIScreen.main.scale)
103 | guard let context = UIGraphicsGetCurrentContext() else {
104 | UIGraphicsEndImageContext()
105 | return nil
106 | }
107 | render(in: context)
108 | let image = UIGraphicsGetImageFromCurrentImageContext()
109 | UIGraphicsEndImageContext()
110 | return image
111 | }
112 | }
113 |
114 | extension BinaryInteger {
115 | var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
116 | }
117 |
--------------------------------------------------------------------------------
/Sources/Switches/Extensions/CGRect+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGRect+Extension.swift
3 | // Switches
4 | //
5 | // Created by Jawad Ali on 05/12/2021.
6 | // Copyright © 2021 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | extension CGRect {
11 | var drawOnPath: CGPath {
12 | let bezierPath = UIBezierPath()
13 |
14 | let radius = self.maxX/5
15 | let center = CGPoint(x: self.midX, y: self.midY)
16 |
17 | let x1 = center.x + radius * cos(-45.degreesToRadians)
18 | let y1 = center.y + radius * sin(-45.degreesToRadians)
19 |
20 | let x2 = center.x + radius * cos(135.degreesToRadians)
21 | let y2 = center.y + radius * sin(135.degreesToRadians)
22 |
23 | let x3 = center.x + (radius + radius * 0.5) * cos(-175.degreesToRadians)
24 | let y3 = center.y + (radius + radius * 0.5) * sin(-175.degreesToRadians)
25 |
26 | bezierPath.move(to: CGPoint(x: x3, y: y3))
27 | bezierPath.addLine(to: CGPoint(x: x2, y: y2))
28 |
29 | bezierPath.addLine(to: CGPoint(x: x1, y: y1))
30 |
31 | return bezierPath.cgPath
32 | }
33 |
34 | var drawOffPath: CGPath {
35 | let bezierPath = UIBezierPath()
36 |
37 | let radius = self.maxX/5
38 | let center = CGPoint(x: self.midX, y: self.midY)
39 |
40 | let x1 = center.x + radius * cos(-45.degreesToRadians)
41 | let y1 = center.y + radius * sin(-45.degreesToRadians)
42 |
43 | let x2 = center.x + radius * cos(135.degreesToRadians)
44 | let y2 = center.y + radius * sin(135.degreesToRadians)
45 |
46 | let x3 = center.x + radius * cos(-135.degreesToRadians)
47 | let y3 = center.y + radius * sin(-135.degreesToRadians)
48 |
49 | let x4 = center.x + radius * cos(45.degreesToRadians)
50 | let y4 = center.y + radius * sin(45.degreesToRadians)
51 |
52 | bezierPath.move(to: CGPoint(x: x3, y: y3))
53 | bezierPath.addLine(to: CGPoint(x: x4, y: y4))
54 |
55 | bezierPath.move(to: CGPoint(x: x1, y: y1))
56 | bezierPath.addLine(to: CGPoint(x: x2, y: y2))
57 |
58 | return bezierPath.cgPath
59 | }
60 |
61 | var bubbleShapePath: CGPath {
62 | let bubblePath = UIBezierPath()
63 | let sR = (size.width - size.height)/4
64 | let lR = size.height/2
65 |
66 | let l1 = CGPoint(x: sR, y: lR - sR)
67 | let l2 = CGPoint(x: sR, y: lR + sR)
68 |
69 | let c1 = CGPoint(x: sR * 2 + lR, y: 0)
70 | let c2 = CGPoint(x: sR * 2 + lR, y: lR * 2)
71 |
72 | let r1 = CGPoint(x: sR * 3 + lR * 2, y: lR - sR)
73 | let r2 = CGPoint(x: sR * 3 + lR * 2, y: lR + sR)
74 |
75 | let o1 = CGPoint(x: (lR + sR * 2)/4, y: lR - sR)
76 | let o2 = CGPoint(x: (lR + sR * 2)/4, y: lR + sR)
77 | let o3 = CGPoint(x: (lR * 2 + sR * 4) - (lR + sR * 2)/4, y: lR - sR)
78 | let o4 = CGPoint(x: (lR * 2 + sR * 4) - (lR + sR * 2)/4, y: lR + sR)
79 |
80 | // let cL = CGPoint(x: sR, y: lR)
81 | let cC = CGPoint(x: sR * 2 + lR, y: lR)
82 | // let cR = CGPoint(x: sR * 3 + lR * 2, y: lR)
83 |
84 | bubblePath.move(to: l1)
85 | bubblePath.addQuadCurve(to: c1, controlPoint: o1)
86 | bubblePath.addArc(withCenter: cC, radius: lR, startAngle: -CGFloat.pi/2, endAngle: CGFloat.pi * 3/2, clockwise: true)
87 | bubblePath.addQuadCurve(to: r1, controlPoint: o3)
88 | bubblePath.addLine(to: r2)
89 |
90 | bubblePath.addQuadCurve(to: c2, controlPoint: o4)
91 | bubblePath.addQuadCurve(to: l2, controlPoint: o2)
92 | bubblePath.addLine(to: l1)
93 | bubblePath.close()
94 |
95 | return bubblePath.cgPath
96 | }
97 |
98 | var drawModeOnPath: CGPath {
99 | let radius = self.maxX/2
100 | let center = CGPoint(x: self.midX, y: self.midY)
101 |
102 | let bezierPath = UIBezierPath()
103 | bezierPath.addArc(withCenter: center, radius: radius, startAngle: 301.degreesToRadians, endAngle: 149.degreesToRadians, clockwise: true)
104 | bezierPath.addArc(withCenter: center, radius: radius, startAngle: 149.degreesToRadians, endAngle: 301.degreesToRadians, clockwise: true)
105 | bezierPath.close()
106 |
107 | return bezierPath.cgPath
108 | }
109 |
110 | var drawModeOffPath: CGPath {
111 | let radius: CGFloat = self.maxX/2
112 |
113 | let centerA = CGPoint(x: self.midX, y: self.midY)
114 | let offset = radius * 1.0/3.0
115 | let centerB = CGPoint(x: centerA.x - offset, y: centerA.y - offset)
116 |
117 | let bezierPath = UIBezierPath()
118 | bezierPath.addArc(withCenter: centerA, radius: radius, startAngle: 301.degreesToRadians, endAngle: 149.degreesToRadians, clockwise: true)
119 | bezierPath.addArc(withCenter: centerB, radius: radius, startAngle: 121.degreesToRadians, endAngle: 329.degreesToRadians, clockwise: false)
120 | bezierPath.close()
121 |
122 | return bezierPath.cgPath
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Sources/Switches/Extensions/UIImage+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 29/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | public extension UIImage {
11 | func maskWithColor(color: UIColor) -> UIImage? {
12 | let maskLayer = CALayer()
13 | maskLayer.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
14 | maskLayer.backgroundColor = color.cgColor
15 | maskLayer.doMask(by: self)
16 | let maskImage = maskLayer.toImage()
17 | return maskImage
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/Switches/JDSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JDSwitch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 22/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | /// `Design by` : Oleg Frolov
10 | // https://dribbble.com/shots/2346044-Switch-on-off
11 |
12 | import UIKit
13 | @IBDesignable open class JDSwitch: BaseControl {
14 | // MARK: - Views
15 |
16 | private lazy var thumbLayer: CALayer = {
17 | let layer = CALayer()
18 | layer.shadowColor = UIColor.black.cgColor
19 | layer.shadowRadius = 2
20 | layer.shadowOpacity = 0.4
21 | layer.shadowOffset = CGSize(width: 0.75, height: 2)
22 | layer.contentsGravity = .resizeAspect
23 | layer.backgroundColor = UIColor.white.cgColor
24 | return layer
25 | }()
26 |
27 | private lazy var trackLayer: CAShapeLayer = {
28 | let shape = CAShapeLayer()
29 |
30 | shape.borderWidth = borderWidth
31 | shape.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
32 | return shape
33 | }()
34 |
35 | var changeThumbColor: Bool = false {
36 | didSet {
37 | setThumbColor()
38 | }
39 | }
40 |
41 | private var isTouchDown: Bool = false {
42 | didSet {
43 | layoutSublayers(of: layer)
44 | changeThumbColor = true
45 | }
46 | }
47 |
48 | // MARK: - Public Properties
49 |
50 | public var shape: shapeType = .rounded {
51 | didSet {
52 | layoutSublayers(of: layer)
53 | }
54 | }
55 |
56 | public var borderWidth: CGFloat = 0 {
57 | didSet {
58 | layoutSublayers(of: layer)
59 | }
60 | }
61 |
62 | public var thumbRadiusPadding: CGFloat = 0 {
63 | didSet {
64 | layoutThumbLayer(for: layer.bounds)
65 | }
66 | }
67 |
68 | public var thumbCornerRadius: CGFloat = 0 {
69 | didSet {
70 | layoutThumbLayer(for: layer.bounds)
71 | }
72 | }
73 |
74 | public var thumbTintColor: UIColor? {
75 | didSet { setThumbColor() }
76 | }
77 |
78 | public var onThumbTintColor: UIColor = #colorLiteral(red: 0.5438016653, green: 0.7640405893, blue: 0.291983664, alpha: 1) {
79 | didSet { setThumbColor() }
80 | }
81 |
82 | public var offThumbTintColor: UIColor = #colorLiteral(red: 0.864574194, green: 0.8753482103, blue: 0.848641932, alpha: 1) {
83 | didSet { setThumbColor() }
84 | }
85 |
86 | // MARK: - initializers
87 |
88 | convenience init() {
89 | self.init(frame: .zero)
90 | }
91 |
92 | override init(frame: CGRect) {
93 | super.init(frame: frame)
94 | controlDidLoad()
95 | }
96 |
97 | public required init?(coder aDecoder: NSCoder) {
98 | super.init(coder: aDecoder)
99 | controlDidLoad()
100 | }
101 |
102 | // MARK: - Common Init
103 |
104 | private func controlDidLoad() {
105 | layer.addSublayer(trackLayer)
106 | layer.addSublayer(thumbLayer)
107 |
108 | layer.shadowOffset = .zero
109 | layer.shadowOpacity = 0.3
110 | layer.shadowRadius = 5
111 | backgroundColor = .clear
112 |
113 | setThumbColor()
114 | addTouchHandlers()
115 | }
116 |
117 | final func getThumbSize() -> CGSize {
118 | let height = bounds.height - 2 * (borderWidth + thumbRadiusPadding)
119 | return CGSize(width: height, height: height)
120 | }
121 |
122 | final func getThumbOrigin(for width: CGFloat) -> CGPoint {
123 | let inset = borderWidth + thumbRadiusPadding
124 | if isTouchDown {
125 | let x = !isOn ? bounds.width - width - inset : inset
126 | return CGPoint(x: x, y: inset)
127 | } else {
128 | let x = isOn ? bounds.width - width - inset : inset
129 | return CGPoint(x: x, y: inset)
130 | }
131 | }
132 |
133 | private func getTackSize() -> CGSize {
134 | isTouchDown ? CGSize(
135 | width: bounds.height,
136 | height: bounds.height
137 | ) : bounds.size
138 | }
139 |
140 | private func getTrackOrigin(for width: CGFloat) -> CGPoint {
141 | let inset: CGFloat = 0.0
142 | let x = !isOn ? bounds.width - width : inset
143 | return CGPoint(x: x, y: inset)
144 | }
145 |
146 | override public func layoutSublayers(of layer: CALayer) {
147 | super.layoutSublayers(of: layer)
148 |
149 | layoutTrackLayer(for: layer.bounds)
150 | layoutThumbLayer(for: layer.bounds)
151 | }
152 | }
153 |
154 | // MARK: - layout Layers
155 |
156 | private extension JDSwitch {
157 | func layoutTrackLayer(for bounds: CGRect) {
158 | let size = getTackSize()
159 | let origin = getTrackOrigin(for: size.width)
160 | trackLayer.frame = CGRect(origin: origin, size: size)
161 |
162 | trackLayer.cornerRadius = shape == .rounded ? trackLayer.bounds.height / 2 : 5
163 | }
164 |
165 | func layoutThumbLayer(for bounds: CGRect) {
166 | let size = getThumbSize()
167 | let origin = getThumbOrigin(for: size.width)
168 | thumbLayer.frame = CGRect(origin: origin, size: size)
169 |
170 | shape == .rounded ? (thumbLayer.cornerRadius = size.height / 2) : (thumbLayer.cornerRadius = thumbCornerRadius)
171 | }
172 | }
173 |
174 | // MARK: - Touches
175 |
176 | private extension JDSwitch {
177 | private func addTouchHandlers() {
178 | addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragEnter])
179 | addTarget(self, action: #selector(touchUp), for: [.touchUpInside])
180 | addTarget(self, action: #selector(touchEnded), for: [.touchDragExit, .touchCancel])
181 |
182 | let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
183 | leftSwipeGesture.direction = [.left]
184 | addGestureRecognizer(leftSwipeGesture)
185 |
186 | let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
187 | rightSwipeGesture.direction = [.right]
188 | addGestureRecognizer(rightSwipeGesture)
189 | }
190 |
191 | @objc
192 | func swipeLeftRight(_ gesture: UISwipeGestureRecognizer) {
193 | let canLeftSwipe = isOn && gesture.direction == .left
194 | let canRightSwipe = !isOn && gesture.direction == .right
195 | guard canLeftSwipe || canRightSwipe else { return }
196 | touchUp()
197 | }
198 |
199 | @objc
200 | func touchDown() {
201 | isTouchDown = true
202 | }
203 |
204 | @objc
205 | func touchUp() {
206 | isOn.toggle()
207 | touchEnded()
208 | }
209 |
210 | @objc
211 | func touchEnded() {
212 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
213 | self.isTouchDown = false
214 | }
215 | }
216 | }
217 |
218 | // MARK: - color setting
219 |
220 | extension JDSwitch {
221 | private func setThumbColor() {
222 | if let thumbColor = thumbTintColor {
223 | thumbLayer.backgroundColor = thumbColor.cgColor
224 | } else {
225 | thumbLayer.backgroundColor = (isOn ? onThumbTintColor : offThumbTintColor).cgColor
226 | }
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/Sources/Switches/SDSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SDSwitch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 22/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | // Crdit design by
10 | /// Mauricio Bucardo
11 | // https://dribbble.com/shots/9841408-Loading-switch-interaction
12 |
13 | /// Alexis Doreau
14 | // https://dribbble.com/shots/3545882-Switch-with-server-calls
15 |
16 | //// George Assan
17 | // https://dribbble.com/shots/5192899-Simple-toggle
18 |
19 | import UIKit
20 | enum LoadingResult {
21 | case success
22 | case failed
23 | }
24 |
25 | public typealias SDSwitchLoadingStarted = () -> Void
26 |
27 | @IBDesignable open class SDSwitch: BaseControl {
28 | open var loadingStarted: SDSwitchLoadingStarted?
29 |
30 | // MARK: - Views
31 |
32 | fileprivate lazy var thumbLayer: CALayer = {
33 | let layer = CALayer()
34 | layer.shadowColor = UIColor.black.cgColor
35 | layer.shadowRadius = 2
36 | layer.shadowOpacity = 0.4
37 | layer.shadowOffset = CGSize(width: 0.75, height: 2)
38 | layer.contentsGravity = .resizeAspect
39 | layer.backgroundColor = UIColor.white.cgColor
40 | return layer
41 | }()
42 |
43 | fileprivate lazy var trackLayer: CALayer = {
44 | let shape = CALayer()
45 | shape.borderWidth = borderWidth
46 | return shape
47 | }()
48 |
49 | private lazy var thumbLoadingCompleteLayer: CAShapeLayer = {
50 | let shape = CAShapeLayer()
51 | shape.lineWidth = thumbRadiusPadding
52 | shape.strokeColor = loadingColor.cgColor
53 | shape.fillColor = UIColor.clear.cgColor
54 | return shape
55 | }()
56 |
57 | private lazy var loadingLayer: CAShapeLayer = {
58 | let shape = CAShapeLayer()
59 | shape.lineWidth = thumbRadiusPadding
60 | shape.strokeColor = loadingColor.cgColor
61 | return shape
62 | }()
63 |
64 | var changeThumbColor: Bool = false {
65 | didSet {
66 | setThumbColor()
67 | }
68 | }
69 |
70 | private var isLoadingCompleted = false
71 |
72 | private var loadingResult: LoadingResult = .success
73 |
74 | fileprivate var isTouchDown: Bool = false {
75 | didSet {
76 | layoutSublayers(of: layer)
77 | changeThumbColor = true
78 | stateDidChange()
79 | }
80 | }
81 |
82 | // MARK: - Public Properties
83 |
84 | public var borderColor: UIColor? {
85 | didSet { setBorderColor() }
86 | }
87 |
88 | public var onBorderColor: UIColor = .white {
89 | didSet { setBorderColor() }
90 | }
91 |
92 | public var offBorderColor: UIColor = .white {
93 | didSet { setBorderColor() }
94 | }
95 |
96 | public var isLoadingEnabled: Bool = false
97 |
98 | public var borderWidth: CGFloat = 2 {
99 | didSet {
100 | trackLayer.borderWidth = borderWidth
101 | layoutSublayers(of: layer)
102 | }
103 | }
104 |
105 | public var thumbRadiusPadding: CGFloat = 4 {
106 | didSet {
107 | layoutSublayers(of: layer)
108 | }
109 | }
110 |
111 | public var thumbCornerRadius: CGFloat = 0 {
112 | didSet {
113 | layoutThumbLayer(for: layer.bounds)
114 | }
115 | }
116 |
117 | public var thumbTintColor: UIColor? {
118 | didSet { setThumbColor() }
119 | }
120 |
121 | public var onThumbTintColor: UIColor = #colorLiteral(red: 0.9999018312, green: 1, blue: 0.9998798966, alpha: 1) {
122 | didSet { setThumbColor() }
123 | }
124 |
125 | public var offThumbTintColor: UIColor = #colorLiteral(red: 0.9999018312, green: 1, blue: 0.9998798966, alpha: 1) {
126 | didSet { setThumbColor() }
127 | }
128 |
129 | public var loadingColor: UIColor = #colorLiteral(red: 0.2855720818, green: 0.8943144679, blue: 0.6083024144, alpha: 1) {
130 | didSet { loadingLayer.strokeColor = loadingColor.cgColor }
131 | }
132 |
133 | public var onTintColor: UIColor = #colorLiteral(red: 0.2855720818, green: 0.8943144679, blue: 0.6083024144, alpha: 1) {
134 | didSet {
135 | trackLayer.backgroundColor = getBackgroundColor()
136 |
137 | setNeedsLayout()
138 | }
139 | }
140 |
141 | public var offTintColor: UIColor = #colorLiteral(red: 0.823615551, green: 0.8911703229, blue: 0.9554550052, alpha: 1) {
142 | didSet {
143 | trackLayer.backgroundColor = getBackgroundColor()
144 | setNeedsLayout()
145 | }
146 | }
147 |
148 | // MARK: - initializers
149 |
150 | convenience init() {
151 | self.init(frame: .zero)
152 | }
153 |
154 | override init(frame: CGRect) {
155 | super.init(frame: frame)
156 | controlDidLoad()
157 | }
158 |
159 | public required init?(coder aDecoder: NSCoder) {
160 | super.init(coder: aDecoder)
161 | controlDidLoad()
162 | }
163 |
164 | // MARK: - Common Init
165 |
166 | fileprivate func controlDidLoad() {
167 | [trackLayer, thumbLayer].forEach(layer.addSublayer)
168 |
169 | layer.shadowColor = UIColor.black.cgColor
170 | layer.shadowOffset = .zero
171 | layer.shadowOpacity = 0.3
172 | layer.shadowRadius = 10
173 | backgroundColor = .clear
174 |
175 | trackLayer.backgroundColor = getBackgroundColor()
176 | setThumbColor()
177 | addTouchHandlers()
178 | }
179 |
180 | fileprivate func getThumbSize() -> CGSize {
181 | let height = bounds.height - 2 * (borderWidth + thumbRadiusPadding)
182 | return CGSize(width: height, height: height)
183 | }
184 |
185 | final func getThumbOrigin(for width: CGFloat) -> CGPoint {
186 | let inset = borderWidth + thumbRadiusPadding
187 | if isTouchDown {
188 | return CGPoint(x: bounds.midX - width/2, y: inset)
189 | } else {
190 | let x = isOn ? bounds.width - width - inset : inset
191 | return CGPoint(x: x, y: inset)
192 | }
193 | }
194 |
195 | fileprivate func getTackSize() -> CGSize {
196 | isTouchDown ? CGSize(width: bounds.height, height: bounds.height) : bounds.size
197 | }
198 |
199 | final func getTrackOrigin(for width: CGFloat) -> CGPoint {
200 | if isTouchDown {
201 | return CGPoint(x: bounds.midX - width/2, y: 0)
202 | }
203 |
204 | let inset: CGFloat = 0.0
205 | let x = !isOn ? bounds.width - width : inset
206 | return CGPoint(x: x, y: inset)
207 | }
208 |
209 | private func stateDidChange() {
210 | trackLayer.backgroundColor = getBackgroundColor()
211 | }
212 |
213 | override public func layoutSublayers(of layer: CALayer) {
214 | super.layoutSublayers(of: layer)
215 |
216 | layoutTrackLayer(for: layer.bounds)
217 | layoutThumbLayer(for: layer.bounds)
218 | layoutLoadingLayer(for: layer.bounds)
219 |
220 | setBorderColor()
221 | }
222 |
223 | @objc public final func loadingCompleted(isSuccessFull: Bool) {
224 | isLoadingCompleted = true
225 | isSuccessFull ? (loadingResult = .success) : (loadingResult = .failed)
226 | if !isSuccessFull {
227 | isOn.toggle()
228 | }
229 |
230 | loadingLayer.removeRotationAnimation()
231 | loadingLayer.removeFromSuperlayer()
232 |
233 | thumbLoadingCompleteLayer.path = (loadingResult == LoadingResult.success) ? thumbLayer.bounds.drawOnPath : thumbLayer.bounds.drawOffPath
234 | thumbLoadingCompleteLayer.lineWidth = thumbRadiusPadding/3
235 | thumbLoadingCompleteLayer.strokeColor = (isSuccessFull ? loadingColor : UIColor.red).cgColor
236 | thumbLoadingCompleteLayer.strokeEnd = 0
237 | thumbLayer.addSublayer(thumbLoadingCompleteLayer)
238 |
239 | CATransaction.setCompletionBlock {
240 | print("completed")
241 | self.isTouchDown = false
242 | self.sendActions(for: .valueChanged)
243 | self.valueChange?(self.isOn)
244 | self.isUserInteractionEnabled = true
245 | }
246 |
247 | CATransaction.begin()
248 | thumbLoadingCompleteLayer.strokeAnimation(duration: 0.3)
249 | CATransaction.commit()
250 | }
251 | }
252 |
253 | // MARK: - layout Layers
254 |
255 | private extension SDSwitch {
256 | func layoutTrackLayer(for bounds: CGRect) {
257 | let size = getTackSize()
258 | let origin = getTrackOrigin(for: size.width)
259 | trackLayer.frame = CGRect(origin: origin, size: size)
260 | trackLayer.cornerRadius = trackLayer.bounds.midY
261 | }
262 |
263 | func layoutThumbLayer(for bounds: CGRect) {
264 | let size = getThumbSize()
265 | let origin = getThumbOrigin(for: size.width)
266 | thumbLayer.frame = CGRect(origin: origin, size: size)
267 | thumbLayer.cornerRadius = thumbLayer.bounds.midY
268 | }
269 |
270 | func layoutLoadingLayer(for bounds: CGRect) {
271 | loadingLayer.lineWidth = thumbRadiusPadding
272 |
273 | let loadingBounds = bounds.insetBy(dx: 0, dy: borderWidth + loadingLayer.lineWidth/2)
274 | let center = CGPoint(x: bounds.midX, y: bounds.midY)
275 | let bezierPath = UIBezierPath(arcCenter: center, radius: bounds.midY, startAngle: -110.degreesToRadians, endAngle: -60.degreesToRadians, clockwise: true)
276 | loadingLayer.frame = loadingBounds
277 | loadingLayer.path = bezierPath.cgPath
278 | }
279 | }
280 |
281 | // MARK: - Touches
282 |
283 | private extension SDSwitch {
284 | private func addTouchHandlers() {
285 | addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragEnter])
286 | addTarget(self, action: #selector(touchUp), for: [.touchUpInside])
287 | addTarget(self, action: #selector(touchEnded), for: [.touchDragExit, .touchCancel])
288 |
289 | let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
290 | leftSwipeGesture.direction = [.left]
291 | addGestureRecognizer(leftSwipeGesture)
292 |
293 | let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
294 | rightSwipeGesture.direction = [.right]
295 | addGestureRecognizer(rightSwipeGesture)
296 | }
297 |
298 | @objc
299 | func swipeLeftRight(_ gesture: UISwipeGestureRecognizer) {
300 | let canLeftSwipe = isOn && gesture.direction == .left
301 | let canRightSwipe = !isOn && gesture.direction == .right
302 | guard canLeftSwipe || canRightSwipe else { return }
303 | touchUp()
304 | }
305 |
306 | @objc
307 | func touchDown() {
308 | isLoadingCompleted = false
309 | if thumbLayer.sublayers?.contains(thumbLoadingCompleteLayer) ?? false {
310 | thumbLoadingCompleteLayer.removeFromSuperlayer()
311 | }
312 |
313 | isTouchDown = true
314 | }
315 |
316 | @objc
317 | func touchUp() {
318 | isOn.toggle()
319 | touchEnded()
320 | }
321 |
322 | @objc
323 | func touchEnded() {
324 | if isLoadingEnabled, isOn {
325 | performLoading()
326 |
327 | } else {
328 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
329 | self.isTouchDown = false
330 | self.valueChange?(self.isOn)
331 | }
332 | }
333 | }
334 | }
335 |
336 | // MARK: - color setting
337 |
338 | private extension SDSwitch {
339 | func setThumbColor() {
340 | if let thumbColor = thumbTintColor {
341 | thumbLayer.backgroundColor = thumbColor.cgColor
342 | } else {
343 | thumbLayer.backgroundColor = (isOn ? onThumbTintColor : offThumbTintColor).cgColor
344 | }
345 | }
346 |
347 | func getBackgroundColor() -> CGColor {
348 | return ((isOn && !isTouchDown) ? onTintColor : offTintColor).cgColor
349 | }
350 |
351 | func setBorderColor() {
352 | if let borderClor = borderColor {
353 | trackLayer.borderColor = borderClor.cgColor
354 | } else {
355 | trackLayer.borderColor = (isOn ? onBorderColor : offBorderColor).cgColor
356 | }
357 | }
358 | }
359 |
360 | // MARK: - Loading Animation
361 |
362 | private extension SDSwitch {
363 | func performLoading() {
364 | loadingStarted?()
365 | layer.addSublayer(loadingLayer)
366 | isUserInteractionEnabled = false
367 | loadingLayer.rotateAnimation(angal: 360.degreesToRadians, duration: 1, repeatAnimation: true)
368 | }
369 | }
370 |
371 | ////`Crdit` :-Morph Switch
372 | // https://dribbble.com/shots/2330566-Morph-Switch
373 | @IBDesignable public class YapFullTextSwitch: SDSwitch {
374 | private lazy var contentsLayer = CATextLayer()
375 |
376 | public var onText: String? {
377 | didSet {
378 | layoutTextLayerIfNeeded()
379 | }
380 | }
381 |
382 | public var offText: String? {
383 | didSet {
384 | layoutTextLayerIfNeeded()
385 | }
386 | }
387 |
388 | public var onTextColor: UIColor = .white
389 |
390 | public var offTextColor: UIColor = .white
391 |
392 | override func controlDidLoad() {
393 | super.controlDidLoad()
394 |
395 | thumbLayer.addSublayer(contentsLayer)
396 | thumbRadiusPadding = 0
397 | }
398 |
399 | override func getThumbSize() -> CGSize {
400 | let height = bounds.height - 2 * borderWidth
401 | let width = isTouchDown ? bounds.width - 2 * borderWidth : height
402 | return CGSize(width: width, height: height)
403 | }
404 |
405 | override func getTackSize() -> CGSize {
406 | bounds.size
407 | }
408 |
409 | override func touchEnded() {
410 | if isOn {
411 | contentsLayer.string = onText
412 | contentsLayer.foregroundColor = onTextColor.cgColor
413 |
414 | } else {
415 | contentsLayer.string = offText
416 | contentsLayer.foregroundColor = offTextColor.cgColor
417 | }
418 |
419 | setBorderColor()
420 | trackLayer.backgroundColor = getBackgroundColor()
421 |
422 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
423 | self.contentsLayer.string = nil
424 | self.isTouchDown = false
425 | self.valueChange?(self.isOn)
426 | }
427 | }
428 |
429 | override public func layoutSublayers(of layer: CALayer) {
430 | super.layoutSublayers(of: layer)
431 | layoutContentLayer(for: bounds)
432 | }
433 |
434 | private func layoutContentLayer(for bounds: CGRect) {
435 | let inset = 2 * borderWidth
436 | let y = bounds.maxY - inset
437 | let leading = borderWidth/2
438 | let x = bounds.maxX - inset
439 | let origin = CGPoint(x: leading, y: leading + bounds.midY/4)
440 |
441 | contentsLayer.frame = CGRect(origin: origin, size: CGSize(width: x, height: y))
442 | contentsLayer.contentsGravity = .center
443 | contentsLayer.fontSize = bounds.height * 0.4
444 | }
445 |
446 | // MARK: - Content Layers
447 |
448 | private func layoutTextLayerIfNeeded() {
449 | contentsLayer.alignmentMode = .center
450 | contentsLayer.fontSize = bounds.height * 0.4
451 | contentsLayer.font = UIFont.systemFont(ofSize: 10, weight: .bold)
452 | contentsLayer.contentsScale = UIScreen.main.scale
453 | }
454 | }
455 |
--------------------------------------------------------------------------------
/Sources/Switches/Switcher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Switcher.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 24/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | /// `Design by` : Oleg Frolov
11 | // https://dribbble.com/shots/3844909-On-Off
12 | // https://dribbble.com/shots/4148855-Switcher-XXXIII
13 |
14 | @IBDesignable public class Switcher: BaseControl {
15 | // MARK: - Properties
16 |
17 | @IBInspectable public var onTintColor: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) {
18 | didSet {
19 | onThumbLayerColorChange()
20 | }
21 | }
22 |
23 | @IBInspectable public var offTintColor: UIColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) {
24 | didSet {
25 | offThumbLayerColorChange()
26 | }
27 | }
28 |
29 | // MARK: - Views
30 |
31 | fileprivate lazy var thumbOnLayer: CALayer = {
32 | let layer = CALayer()
33 | layer.contentsGravity = .resizeAspect
34 | layer.backgroundColor = onTintColor.cgColor
35 | return layer
36 | }()
37 |
38 | fileprivate lazy var thumbOffLayer: CALayer = {
39 | let layer = CALayer()
40 |
41 | layer.contentsGravity = .resizeAspect
42 | layer.backgroundColor = offTintColor.cgColor
43 | return layer
44 | }()
45 |
46 | private lazy var trackLayer: CAShapeLayer = {
47 | let shape = CAShapeLayer()
48 | shape.backgroundColor = UIColor.white.cgColor
49 | return shape
50 | }()
51 |
52 | fileprivate var thumbRadiusPadding: CGFloat = 10
53 | fileprivate var duration: Double = 1
54 | fileprivate var isTouchDown: Bool = false {
55 | didSet {
56 | layoutSublayers(of: layer)
57 | }
58 | }
59 |
60 | // MARK: - initializers
61 |
62 | convenience init() {
63 | self.init(frame: .zero)
64 | }
65 |
66 | override init(frame: CGRect) {
67 | super.init(frame: frame)
68 | controlDidLoad()
69 | }
70 |
71 | required init?(coder aDecoder: NSCoder) {
72 | super.init(coder: aDecoder)
73 | controlDidLoad()
74 | }
75 |
76 | fileprivate func controlDidLoad() {
77 | layer.addSublayer(trackLayer)
78 | layer.addSublayer(thumbOffLayer)
79 | layer.addSublayer(thumbOnLayer)
80 |
81 | layer.shadowOffset = .zero
82 | layer.shadowOpacity = 0.3
83 | layer.shadowRadius = 5
84 | layer.masksToBounds = true
85 |
86 | isOn ? (trackLayer.backgroundColor = offTintColor.cgColor) : (trackLayer.backgroundColor = onTintColor.cgColor)
87 | addTouchHandlers()
88 | backgroundColor = .clear
89 | }
90 |
91 | override public func layoutSublayers(of layer: CALayer) {
92 | super.layoutSublayers(of: layer)
93 | layer.cornerRadius = bounds.midY
94 | CATransaction.setAnimationDuration(duration)
95 | CATransaction.begin()
96 |
97 | layoutLayers()
98 |
99 | CATransaction.commit()
100 | }
101 |
102 | fileprivate func layoutLayers() {
103 | layoutTrackLayer(for: layer.bounds)
104 | layoutOnThumbLayer(for: layer.bounds)
105 | layoutOffThumbLayer(for: layer.bounds)
106 | }
107 |
108 | fileprivate func onThumbLayerColorChange() {
109 | thumbOnLayer.backgroundColor = onTintColor.cgColor
110 | isOn ? (trackLayer.backgroundColor = offTintColor.cgColor) : (trackLayer.backgroundColor = onTintColor.cgColor)
111 | }
112 |
113 | fileprivate func offThumbLayerColorChange() {
114 | thumbOffLayer.backgroundColor = offTintColor.cgColor
115 | isOn ? (trackLayer.backgroundColor = offTintColor.cgColor) : (trackLayer.backgroundColor = onTintColor.cgColor)
116 | }
117 | }
118 |
119 | // MARK: - layout Layers
120 |
121 | private extension Switcher {
122 | func layoutTrackLayer(for bounds: CGRect) {
123 | trackLayer.frame = bounds
124 | trackLayer.cornerRadius = trackLayer.bounds.midY
125 | }
126 |
127 | @objc func layoutOnThumbLayer(for bounds: CGRect) {
128 | let size = getOnThumbSize()
129 | let origin = getOnThumbOrigin(for: size.width)
130 | thumbOnLayer.frame = CGRect(origin: origin, size: size)
131 | thumbOnLayer.cornerRadius = size.height/2
132 | }
133 |
134 | @objc func layoutOffThumbLayer(for bounds: CGRect) {
135 | let size = getOffThumbSize()
136 | let origin = getOffThumbOrigin(for: size.width)
137 | thumbOffLayer.frame = CGRect(origin: origin, size: size)
138 | thumbOffLayer.cornerRadius = size.height/2
139 | }
140 |
141 | final func getOnThumbSize() -> CGSize {
142 | let height = bounds.height - 2 * thumbRadiusPadding
143 | return (isTouchDown && !isOn) ? CGSize(width: bounds.maxX * 1.5, height: bounds.maxY * 2) : CGSize(width: height, height: height)
144 | }
145 |
146 | final func getOffThumbSize() -> CGSize {
147 | let height = bounds.height - 2 * thumbRadiusPadding
148 | return (isTouchDown && isOn) ? CGSize(width: bounds.maxX * 1.5, height: bounds.maxY * 2) : CGSize(width: height, height: height)
149 | }
150 |
151 | final func getOnThumbOrigin(for width: CGFloat) -> CGPoint {
152 | let inset = thumbRadiusPadding
153 | return (isTouchDown && !isOn) ? CGPoint(x: -bounds.maxX/3, y: -bounds.midY * 0.8) : CGPoint(x: bounds.width - width - inset, y: inset)
154 | }
155 |
156 | final func getOffThumbOrigin(for width: CGFloat) -> CGPoint {
157 | let inset = thumbRadiusPadding
158 | return (isTouchDown && isOn) ? CGPoint(x: -bounds.maxX/3, y: -bounds.midY * 0.8) : CGPoint(x: inset, y: inset)
159 | }
160 | }
161 |
162 | private extension Switcher {
163 | private func addTouchHandlers() {
164 | addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragEnter])
165 | addTarget(self, action: #selector(touchUp), for: [.touchUpInside])
166 | addTarget(self, action: #selector(touchEnded), for: [.touchDragExit, .touchCancel])
167 |
168 | let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
169 | leftSwipeGesture.direction = [.left]
170 | addGestureRecognizer(leftSwipeGesture)
171 |
172 | let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
173 | rightSwipeGesture.direction = [.right]
174 | addGestureRecognizer(rightSwipeGesture)
175 | }
176 |
177 | @objc
178 | func swipeLeftRight(_ gesture: UISwipeGestureRecognizer) {
179 | let canLeftSwipe = isOn && gesture.direction == .left
180 | let canRightSwipe = !isOn && gesture.direction == .right
181 | guard canLeftSwipe || canRightSwipe else { return }
182 | touchUp()
183 | }
184 |
185 | @objc
186 | func touchDown() {
187 | isUserInteractionEnabled = false
188 |
189 | UIView.animate(withDuration: 0.2,
190 | animations: {
191 | self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
192 | })
193 | }
194 |
195 | @objc
196 | func touchUp() {
197 | isOn.toggle()
198 | touchEnded()
199 | }
200 |
201 | @objc
202 | func touchEnded() {
203 | isTouchDown = true
204 |
205 | UIView.animate(withDuration: duration/3,
206 | animations: {
207 | self.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
208 | },
209 | completion: { _ in
210 | UIView.animate(withDuration: self.duration/3) {
211 | self.transform = CGAffineTransform.identity
212 | }
213 | })
214 |
215 | DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
216 | self.isOn ? (self.trackLayer.backgroundColor = self.offTintColor.cgColor) : (self.trackLayer.backgroundColor = self.onTintColor.cgColor)
217 |
218 | self.isOn ? (self.thumbOffLayer.areAnimationsEnabled = false) : (self.thumbOnLayer.areAnimationsEnabled = false)
219 | self.sendActions(for: .valueChanged)
220 |
221 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
222 | self.isUserInteractionEnabled = true
223 |
224 | self.isTouchDown = false
225 | self.isOn ? self.thumbOffLayer.bringToFront() : self.thumbOnLayer.bringToFront()
226 | self.isOn ? (self.thumbOffLayer.areAnimationsEnabled = true) : (self.thumbOnLayer.areAnimationsEnabled = true)
227 | }
228 | }
229 | }
230 | }
231 |
232 | @IBDesignable public class SwitcherFullStrtech: Switcher {
233 | @IBInspectable public var thumbTintColor: UIColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) {
234 | didSet {
235 | ThumbLayerColorChange()
236 | }
237 | }
238 |
239 | private lazy var interactionLayer: CALayer = {
240 | let shape = CALayer()
241 | shape.backgroundColor = thumbTintColor.cgColor
242 | return shape
243 |
244 | }()
245 |
246 | override func controlDidLoad() {
247 | super.controlDidLoad()
248 | layer.addSublayer(interactionLayer)
249 |
250 | thumbOnLayer.bringToFront()
251 | thumbOffLayer.bringToFront()
252 | duration = 0.5
253 | thumbRadiusPadding = 0
254 |
255 | layer.masksToBounds = false
256 | }
257 |
258 | override func layoutLayers() {
259 | super.layoutLayers()
260 | layoutInteractionLayerLayer(for: bounds)
261 | }
262 |
263 | override func layoutOnThumbLayer(for bounds: CGRect) {
264 | let percent: CGFloat = bounds.maxY * 0.2
265 |
266 | thumbOnLayer.frame = CGRect(x: bounds.midY - percent/2, y: bounds.midY - percent/2, width: percent, height: percent)
267 | thumbOnLayer.cornerRadius = thumbOnLayer.bounds.midY
268 | }
269 |
270 | override func layoutOffThumbLayer(for bounds: CGRect) {
271 | let heightPercent: CGFloat = bounds.maxY * 0.4
272 | let widthPercent: CGFloat = bounds.maxY * 0.12
273 |
274 | thumbOffLayer.frame = CGRect(x: bounds.maxX - bounds.midY - widthPercent/2, y: bounds.midY - heightPercent/2, width: widthPercent, height: heightPercent)
275 | thumbOffLayer.cornerRadius = thumbOffLayer.bounds.midX
276 | }
277 |
278 | override fileprivate func onThumbLayerColorChange() {
279 | thumbOnLayer.backgroundColor = onTintColor.cgColor
280 | }
281 |
282 | override fileprivate func offThumbLayerColorChange() {
283 | thumbOffLayer.backgroundColor = offTintColor.cgColor
284 | }
285 |
286 | override func touchEnded() {
287 | isTouchDown = true
288 | DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
289 | self.isTouchDown = false
290 | self.isUserInteractionEnabled = true
291 |
292 | let onTint = self.onTintColor
293 | self.onTintColor = self.offTintColor
294 | self.offTintColor = onTint
295 | }
296 | }
297 |
298 | func ThumbLayerColorChange() {
299 | interactionLayer.backgroundColor = thumbTintColor.cgColor
300 | }
301 | }
302 |
303 | extension SwitcherFullStrtech {
304 | func layoutInteractionLayerLayer(for bounds: CGRect) {
305 | interactionLayer.cornerRadius = bounds.midY
306 |
307 | isTouchDown ? (interactionLayer.frame = bounds) : (isOn ? (interactionLayer.frame = CGRect(x: bounds.maxX - bounds.maxY, y: 0, width: bounds.maxY, height: bounds.maxY)) : (interactionLayer.frame = CGRect(x: 0, y: 0, width: bounds.maxY, height: bounds.maxY)))
308 | }
309 | }
310 |
--------------------------------------------------------------------------------
/Sources/Switches/YapBaseSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YapBaseSwitch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 13/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | //// `Design by`: Oleg Frolov
10 | // https://dribbble.com/shots/2028065-Switcher-lll
11 |
12 | import UIKit
13 |
14 | @IBDesignable
15 | open class YapBaseSwitch: BaseControl {
16 | // MARK: - Property
17 |
18 | @IBInspectable open var animateDuration: Double = 0.4
19 |
20 | internal var on: Bool = false
21 | internal var sizeScale: CGFloat {
22 | return min(self.bounds.width, self.bounds.height) / 100.0
23 | }
24 |
25 | override open var frame: CGRect {
26 | didSet {
27 | guard frame.size != oldValue.size else { return }
28 | resetView()
29 | }
30 | }
31 |
32 | override open var bounds: CGRect {
33 | didSet {
34 | guard frame.size != oldValue.size else { return }
35 | resetView()
36 | }
37 | }
38 |
39 | // MARK: - Getter
40 |
41 | public final func setOn(_ on: Bool, animate: Bool = true) {
42 | guard on != isOn else { return }
43 | toggleValue()
44 | }
45 |
46 | // MARK: - Init
47 |
48 | public convenience init() {
49 | self.init(frame: CGRect(x: 0, y: 0, width: 80, height: 40))
50 | }
51 |
52 | override public init(frame: CGRect) {
53 | super.init(frame: frame)
54 | setUpView()
55 | }
56 |
57 | public required init?(coder aDecoder: NSCoder) {
58 | super.init(coder: aDecoder)
59 | setUpView()
60 | }
61 |
62 | // MARK: - Internal
63 |
64 | internal func resetView() {
65 | gestureRecognizers?.forEach(removeGestureRecognizer)
66 | layer.sublayers?.forEach { $0.removeFromSuperlayer() }
67 | setUpView()
68 | }
69 |
70 | internal func setUpView() {
71 | let tap = UITapGestureRecognizer(target: self, action: #selector(YapBaseSwitch.toggleValue))
72 | addGestureRecognizer(tap)
73 |
74 | for view in subviews {
75 | view.removeFromSuperview()
76 | }
77 | }
78 |
79 | @objc internal func toggleValue() {
80 | on.toggle()
81 | isOn.toggle()
82 | valueChange?(isOn)
83 | sendActions(for: .valueChanged)
84 | changeValueAnimate(isOn, duration: animateDuration)
85 | }
86 |
87 | internal func changeValueAnimate(_ value: Bool, duration: Double) {}
88 | }
89 |
--------------------------------------------------------------------------------
/Sources/Switches/YapLiquidSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TKLiquidSwitch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 13/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // Dedign by Oleg Frolov
12 | // https://dribbble.com/shots/2028065-Switcher-lll
13 |
14 | @IBDesignable
15 | open class YapLiquidSwitch: YapBaseSwitch {
16 | private var bubbleLayer = CAShapeLayer()
17 | private var lineLayer = CAShapeLayer()
18 | @IBInspectable open var onColor = UIColor(red: 0.373, green: 0.843, blue: 0.596, alpha: 1) {
19 | didSet {
20 | resetView()
21 | }
22 | }
23 |
24 | @IBInspectable open var offColor = UIColor(red: 0.871, green: 0.871, blue: 0.871, alpha: 1) {
25 | didSet {
26 | resetView()
27 | }
28 | }
29 |
30 | override internal func setUpView() {
31 | super.setUpView()
32 |
33 | clipsToBounds = true
34 |
35 | lineLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: (bounds.height - 20 * sizeScale)/2, width: bounds.width, height: 20 * sizeScale), cornerRadius: 10 * sizeScale).cgPath
36 | lineLayer.fillColor = switchColor(isOn).cgColor
37 | layer.addSublayer(lineLayer)
38 |
39 | bubbleLayer.frame = bounds
40 | bubbleLayer.position = bubblePosition(isOn)
41 | bubbleLayer.path = CGRect(origin: .zero, size: bubbleSize).bubbleShapePath
42 | bubbleLayer.fillColor = switchColor(isOn).cgColor
43 | layer.addSublayer(bubbleLayer)
44 | }
45 |
46 | override func changeValueAnimate(_ value: Bool, duration: Double) {
47 | let bubbleTransformAnim = CAKeyframeAnimation(keyPath: "transform")
48 | bubbleTransformAnim.values = [NSValue(caTransform3D: CATransform3DIdentity),
49 | NSValue(caTransform3D: CATransform3DMakeScale(1, 0.8, 1)),
50 | NSValue(caTransform3D: CATransform3DMakeScale(0.8, 1, 1)),
51 | NSValue(caTransform3D: CATransform3DIdentity)]
52 | bubbleTransformAnim.keyTimes = [NSNumber(value: 0), NSNumber(value: 1.0/3.0), NSNumber(value: 2.0/3.0), NSNumber(value: 1)]
53 | bubbleTransformAnim.duration = duration
54 |
55 | let bubblePositionAnim = CABasicAnimation(keyPath: "position")
56 | bubblePositionAnim.fromValue = NSValue(cgPoint: bubblePosition(!isOn))
57 | bubblePositionAnim.toValue = NSValue(cgPoint: bubblePosition(isOn))
58 | bubblePositionAnim.duration = duration
59 |
60 | let bubbleGroupAnim = CAAnimationGroup()
61 | bubbleGroupAnim.animations = [bubbleTransformAnim, bubblePositionAnim]
62 | bubbleGroupAnim.isRemovedOnCompletion = false
63 | bubbleGroupAnim.fillMode = CAMediaTimingFillMode.forwards
64 | bubbleGroupAnim.duration = duration
65 |
66 | bubbleLayer.add(bubbleGroupAnim, forKey: "Bubble")
67 |
68 | let color = switchColor(value).cgColor
69 | UIView.animate(withDuration: duration, animations: { () -> Void in
70 | self.lineLayer.fillColor = color
71 | self.bubbleLayer.fillColor = color
72 | })
73 | }
74 | }
75 |
76 | // Getter
77 | extension YapLiquidSwitch {
78 | var bubbleSize: CGSize {
79 | let lineH = 20 * sizeScale
80 | let w = lineH * 2 + bounds.height
81 | let h = bounds.height
82 | return CGSize(width: w, height: h)
83 | }
84 |
85 | func switchColor(_ isOn: Bool) -> UIColor {
86 | if isOn {
87 | return onColor
88 | } else {
89 | return offColor
90 | }
91 | }
92 |
93 | func bubblePosition(_ isOn: Bool) -> CGPoint {
94 | let h = bounds.height
95 | let w = bounds.width
96 | let bW = bubbleSize.width
97 |
98 | if isOn {
99 | return CGPoint(x: bW * 0.8, y: h/2)
100 | } else {
101 | return CGPoint(x: w - bW * 0.2, y: h/2)
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Sources/Switches/YapSmileSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SmileSwitch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 13/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // Dedign by Oleg Frolov
12 | // https://dribbble.com/shots/2011284-Switcher-ll
13 |
14 | open class YapSmileSwitch: YapBaseSwitch {
15 | // MARK: - Poperty
16 |
17 | private var smileFace: TKSmileFaceView?
18 |
19 | // MARK: - Init
20 |
21 | override internal func setUpView() {
22 | super.setUpView()
23 | backgroundColor = .clear
24 | let frame = CGRect(x: bounds.width - bounds.height, y: 0, width: bounds.height, height: bounds.height)
25 | smileFace = TKSmileFaceView(frame: frame)
26 | addSubview(smileFace!)
27 | }
28 |
29 | override open func draw(_ rect: CGRect) {
30 | let ctx = UIGraphicsGetCurrentContext()
31 | let lineWidth = 10 * sizeScale
32 | let path = UIBezierPath(roundedRect: rect.insetBy(dx: lineWidth, dy: lineWidth), cornerRadius: rect.width/2)
33 | ctx?.setLineWidth(lineWidth * 2)
34 | ctx?.addPath(path.cgPath)
35 | UIColor(white: 0.9, alpha: 1).setStroke()
36 | ctx?.strokePath()
37 | }
38 |
39 | override func changeValueAnimate(_ value: Bool, duration: Double) {
40 | let x = value ? 0 : (bounds.width - bounds.height)
41 | let frame = CGRect(x: x, y: 0, width: bounds.height, height: bounds.height)
42 | smileFace!.faceType = value ? TKSmileFaceView.FaceType.happy : TKSmileFaceView.FaceType.sad
43 | smileFace?.rotation(animateDuration, count: 2, clockwise: !isOn)
44 | UIView.animate(withDuration: duration, animations: { () -> Void in
45 | self.smileFace?.frame = frame
46 | }, completion: { complete -> Void in
47 | if complete {
48 | self.smileFace?.eyeWinkAnimate(duration/2)
49 | }
50 | })
51 | }
52 | }
53 |
54 | // 脸
55 | private class TKSmileFaceView: UIView {
56 | enum FaceType {
57 | case happy
58 | case sad
59 | func toColor() -> UIColor {
60 | switch self {
61 | case .happy:
62 | return UIColor(red: 0.388, green: 0.839, blue: 0.608, alpha: 1.000)
63 | case .sad:
64 | return UIColor(red: 0.843, green: 0.369, blue: 0.373, alpha: 1)
65 | }
66 | }
67 | }
68 |
69 | // MARK: - Property
70 |
71 | let rightEye = CAShapeLayer()
72 | let leftEye = CAShapeLayer()
73 | let mouth = CAShapeLayer()
74 | let face = CAShapeLayer()
75 |
76 | var faceType: FaceType = .sad {
77 | didSet {
78 | let position: CGFloat = isHappy ? 20 * sizeScale : 35 * sizeScale
79 | mouth.path = mouthPath.cgPath
80 | mouth.frame = CGRect(x: 0, y: position, width: 60 * sizeScale, height: 20 * sizeScale)
81 | face.fillColor = faceType.toColor().cgColor
82 | }
83 | }
84 |
85 | // MARK: - Getter
86 |
87 | var isHappy: Bool {
88 | return (faceType == .happy)
89 | }
90 |
91 | var sizeScale: CGFloat {
92 | return min(bounds.width, bounds.height)/100.0
93 | }
94 |
95 | var mouthPath: UIBezierPath {
96 | let point: CGFloat = isHappy ? 70 * sizeScale : 10
97 | let path = UIBezierPath()
98 | path.move(to: CGPoint(x: 30 * sizeScale, y: 40 * sizeScale))
99 | path.addCurve(to: CGPoint(x: 70 * sizeScale, y: 40 * sizeScale), controlPoint1: CGPoint(x: 30 * sizeScale, y: 40 * sizeScale), controlPoint2: CGPoint(x: 50 * sizeScale, y: point))
100 | path.lineCapStyle = .round
101 | return path
102 | }
103 |
104 | // MARK: - Init
105 |
106 | override init(frame: CGRect) {
107 | super.init(frame: frame)
108 | setupLayers()
109 | }
110 |
111 | required init?(coder aDecoder: NSCoder) {
112 | super.init(coder: aDecoder)
113 | setupLayers()
114 | }
115 |
116 | // MARK: - Private Func
117 |
118 | private func setupLayers() {
119 | let facePath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 100 * sizeScale, height: 100 * sizeScale))
120 | let eyePath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 20 * sizeScale, height: 20 * sizeScale))
121 |
122 | face.frame = CGRect(x: 0, y: 0, width: 100 * sizeScale, height: 100 * sizeScale)
123 | face.path = facePath.cgPath
124 | face.fillColor = faceType.toColor().cgColor
125 | layer.addSublayer(face)
126 |
127 | leftEye.frame = CGRect(x: 20 * sizeScale, y: 28 * sizeScale, width: 10 * sizeScale, height: 10 * sizeScale)
128 | leftEye.path = eyePath.cgPath
129 | leftEye.fillColor = UIColor.white.cgColor
130 | layer.addSublayer(leftEye)
131 |
132 | rightEye.frame = CGRect(x: 60 * sizeScale, y: 28 * sizeScale, width: 10 * sizeScale, height: 10 * sizeScale)
133 | rightEye.path = eyePath.cgPath
134 | rightEye.fillColor = UIColor.white.cgColor
135 | layer.addSublayer(rightEye)
136 |
137 | mouth.path = mouthPath.cgPath
138 | mouth.strokeColor = UIColor.white.cgColor
139 | mouth.fillColor = UIColor.clear.cgColor
140 | mouth.lineCap = .round
141 | mouth.lineWidth = 10 * sizeScale
142 | layer.addSublayer(mouth)
143 |
144 | faceType = .sad
145 | }
146 |
147 | // MARK: - Animate
148 |
149 | func eyeWinkAnimate(_ duration: Double) {
150 | let eyeleftTransformAnim = CAKeyframeAnimation(keyPath: "transform")
151 | eyeleftTransformAnim.values = [NSValue(caTransform3D: CATransform3DIdentity),
152 | NSValue(caTransform3D: CATransform3DMakeScale(1, 0.1, 1)),
153 | NSValue(caTransform3D: CATransform3DIdentity)]
154 | eyeleftTransformAnim.keyTimes = [0, 0.5, 1]
155 | eyeleftTransformAnim.duration = duration
156 | leftEye.add(eyeleftTransformAnim, forKey: "Wink")
157 | rightEye.add(eyeleftTransformAnim, forKey: "Wink")
158 | }
159 |
160 | func rotation(_ duration: Double, count: Int, clockwise: Bool) {
161 | let rotationTransformAnim = CAKeyframeAnimation(keyPath: "transform.rotation.z")
162 | rotationTransformAnim.values = [0, 180 * CGFloat.pi/180 * CGFloat(count) * (clockwise ? 1 : -1)]
163 | rotationTransformAnim.keyTimes = [0, 1]
164 | rotationTransformAnim.isRemovedOnCompletion = false
165 | rotationTransformAnim.duration = duration
166 | layer.add(rotationTransformAnim, forKey: "Rotation")
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/Sources/Switches/YapSwitch.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Switch.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 13/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | //// `Design by`: Anupam
10 | // https://dribbble.com/shots/4908263-Switch-UI
11 |
12 | //// `Design by` : Maria Kovalevich
13 | // https://dribbble.com/shots/4685786-Daily-UI-015-On-Off-Switch-clickable-prototype
14 | import Foundation
15 | import UIKit
16 | public enum shapeType {
17 | case square
18 | case rounded
19 | }
20 |
21 | @IBDesignable public class YapSwitch: BaseControl {
22 | // MARK: - Properties
23 |
24 | //// corner radius of thumbnail in case of square
25 | //// It has no effect if shape is rounded
26 |
27 | public var thumbCornerRadius: CGFloat = 0 {
28 | didSet {
29 | layoutThumbLayer(for: layer.bounds)
30 | }
31 | }
32 |
33 | //// if stretch is enable .. on touch down thumbnail increase its width....
34 | public var isStretchEnable: Bool = true
35 |
36 | /// `shape` of your switch ... it can either be rounded or square .. you can set it accordingly
37 |
38 | public var shape: shapeType = .rounded {
39 | didSet {
40 | layoutSublayers(of: layer)
41 | }
42 | }
43 |
44 | /// Width of the border... it can have any `float` value
45 | public var borderWidth: CGFloat = 0 {
46 | didSet {
47 | trackLayer.borderWidth = borderWidth
48 | layoutSublayers(of: layer)
49 | }
50 | }
51 |
52 | public var borderColor: UIColor? {
53 | didSet { setBorderColor() }
54 | }
55 |
56 | public var onBorderColor: UIColor = .white {
57 | didSet { setBorderColor() }
58 | }
59 |
60 | public var offBorderColor: UIColor = .white {
61 | didSet { setBorderColor() }
62 | }
63 |
64 | public var textColor: UIColor? {
65 | didSet {
66 | (offContentLayer as? CATextLayer)?.foregroundColor = textColor?.cgColor
67 | (onContentLayer as? CATextLayer)?.foregroundColor = textColor?.cgColor
68 | }
69 | }
70 |
71 | public var onTextColor: UIColor = .white {
72 | didSet {
73 | (onContentLayer as? CATextLayer)?.foregroundColor = onTextColor.cgColor
74 | }
75 | }
76 |
77 | public var offTextColor: UIColor = .white {
78 | didSet {
79 | (offContentLayer as? CATextLayer)?.foregroundColor = offTextColor.cgColor
80 | }
81 | }
82 |
83 | public var trackTopBottomPadding: CGFloat = 0 {
84 | didSet {
85 | layoutSublayers(of: layer)
86 | }
87 | }
88 |
89 | public var contentLeadingTrailingPadding: CGFloat = 0 {
90 | didSet {
91 | layoutSublayers(of: layer)
92 | }
93 | }
94 |
95 | //// Distance of `thumb` from track layer
96 | public var thumbRadiusPadding: CGFloat = 3.5 {
97 | didSet {
98 | layoutThumbLayer(for: layer.bounds)
99 | }
100 | }
101 |
102 | public var onTintColor = UIColor(red: 0, green: 122/255, blue: 1, alpha: 1) {
103 | didSet {
104 | trackLayer.backgroundColor = getBackgroundColor()
105 |
106 | setNeedsLayout()
107 | }
108 | }
109 |
110 | public var offTintColor: UIColor = .white {
111 | didSet {
112 | trackLayer.backgroundColor = getBackgroundColor()
113 | setNeedsLayout()
114 | }
115 | }
116 |
117 | public var thumbTintColor: UIColor? {
118 | didSet { setThumbColor() }
119 | }
120 |
121 | public var onThumbTintColor: UIColor = .white {
122 | didSet { setThumbColor() }
123 | }
124 |
125 | public var offThumbTintColor: UIColor = .white {
126 | didSet { setThumbColor() }
127 | }
128 |
129 | public var onText: String? {
130 | didSet {
131 | addOnTextLayerIfNeeded()
132 | (onContentLayer as? CATextLayer)?.string = onText
133 | }
134 | }
135 |
136 | public var offText: String? {
137 | didSet {
138 | addOffTextLayerIfNeeded()
139 | (offContentLayer as? CATextLayer)?.string = offText
140 | }
141 | }
142 |
143 | public var onThumbImage: UIImage? {
144 | didSet {
145 | thumbLayer.contents = onThumbImage?.cgImage
146 | }
147 | }
148 |
149 | public var offThumbImage: UIImage? {
150 | didSet {
151 | thumbLayer.contents = offThumbImage?.cgImage
152 | }
153 | }
154 |
155 | public var thumbImage: UIImage? {
156 | didSet {
157 | thumbLayer.contents = thumbImage?.cgImage
158 | }
159 | }
160 |
161 | public var onImage: UIImage? {
162 | didSet {
163 | addOnImageLayerIfNeeded()
164 | onContentLayer?.contents = onImage?.cgImage
165 | }
166 | }
167 |
168 | public var offImage: UIImage? {
169 | didSet {
170 | addOffImageLayerIfNeeded()
171 | offContentLayer?.contents = offImage?.cgImage
172 | }
173 | }
174 |
175 | override public var intrinsicContentSize: CGSize {
176 | return CGSize(width: 52, height: 31)
177 | }
178 |
179 | // MARK: - Layers
180 |
181 | //// `trackLayer`:- is main track layer
182 | //// `innerLayer`:- over track layer
183 | ////`thumLayer` :- it is used for thumb
184 |
185 | fileprivate lazy var trackLayer = CALayer()
186 | fileprivate lazy var innerLayer = CALayer()
187 | fileprivate lazy var thumbLayer: CALayer = {
188 | let layer = CALayer()
189 | layer.shadowColor = UIColor.black.cgColor
190 | layer.shadowRadius = 2
191 | layer.shadowOpacity = 0.4
192 | layer.shadowOffset = CGSize(width: 0.75, height: 2)
193 | layer.contentsGravity = .resizeAspect
194 | return layer
195 | }()
196 |
197 | private lazy var contentsLayer = CALayer()
198 |
199 | private var onContentLayer: CALayer? {
200 | willSet {
201 | onContentLayer?.removeFromSuperlayer()
202 | }
203 | didSet {
204 | layoutOnContentLayer(for: layer.bounds)
205 | }
206 | }
207 |
208 | private var offContentLayer: CALayer? {
209 | willSet {
210 | offContentLayer?.removeFromSuperlayer()
211 | }
212 | didSet {
213 | layoutOffContentLayer(for: layer.bounds)
214 | }
215 | }
216 |
217 | fileprivate var isTouchDown: Bool = false
218 |
219 | // MARK: - initializers
220 |
221 | convenience init() {
222 | self.init(frame: .zero)
223 | frame.size = intrinsicContentSize
224 | }
225 |
226 | override init(frame: CGRect) {
227 | super.init(frame: frame)
228 | controlDidLoad()
229 | }
230 |
231 | required init?(coder aDecoder: NSCoder) {
232 | super.init(coder: aDecoder)
233 | controlDidLoad()
234 | }
235 |
236 | // MARK: - Common Init
237 |
238 | fileprivate func controlDidLoad() {
239 | layer.shadowOffset = .zero
240 | layer.shadowOpacity = 0.3
241 | layer.shadowRadius = 5
242 |
243 | backgroundColor = .clear
244 |
245 | layer.addSublayer(trackLayer)
246 | layer.addSublayer(innerLayer)
247 | layer.addSublayer(contentsLayer)
248 | layer.addSublayer(thumbLayer)
249 |
250 | trackLayer.backgroundColor = getBackgroundColor()
251 | setBorderColor()
252 | trackLayer.borderWidth = borderWidth
253 |
254 | innerLayer.backgroundColor = UIColor.white.cgColor
255 |
256 | contentsLayer.masksToBounds = true
257 |
258 | setThumbColor()
259 | addTouchHandlers()
260 | layoutSublayers(of: layer)
261 | }
262 |
263 | // MARK: - layoutSubviews
264 |
265 | override public func layoutSublayers(of layer: CALayer) {
266 | super.layoutSublayers(of: layer)
267 |
268 | layoutTrackLayer(for: layer.bounds)
269 | layoutThumbLayer(for: layer.bounds)
270 | contentsLayer.frame = layer.bounds
271 | layoutOffContentLayer(for: layer.bounds)
272 | layoutOnContentLayer(for: layer.bounds)
273 | }
274 |
275 | override public func didMoveToSuperview() {
276 | layoutSublayers(of: layer)
277 | }
278 |
279 | fileprivate func layoutTrackLayer(for bounds: CGRect) {
280 | trackLayer.frame = bounds.insetBy(dx: trackTopBottomPadding, dy: trackTopBottomPadding)
281 | shape == .rounded ? (trackLayer.cornerRadius = trackLayer.bounds.height/2) : (trackLayer.cornerRadius = bounds.height * 0.12)
282 | }
283 |
284 | fileprivate func layoutInnerLayer(for bounds: CGRect) {
285 | let inset = borderWidth + trackTopBottomPadding
286 | let isInnerHidden = isOn || (isTouchDown && isStretchEnable)
287 |
288 | innerLayer.frame = isInnerHidden
289 | ? CGRect(origin: trackLayer.position, size: .zero)
290 | : bounds.insetBy(dx: inset, dy: inset)
291 |
292 | shape == .rounded ? (innerLayer.cornerRadius = isInnerHidden ? 0 : bounds.height/2 - inset) : (innerLayer.cornerRadius = isInnerHidden ? 5 : 5)
293 | }
294 |
295 | fileprivate func layoutThumbLayer(for bounds: CGRect) {
296 | let size = getThumbSize()
297 | let origin = getThumbOrigin(for: size.width)
298 | thumbLayer.frame = CGRect(origin: origin, size: size)
299 |
300 | if let thumb = thumbImage {
301 | onThumbImage = thumb
302 | offThumbImage = thumb
303 | }
304 |
305 | thumbLayer.contents = isOn ? onThumbImage?.cgImage : offThumbImage?.cgImage
306 |
307 | shape == .rounded ? (thumbLayer.cornerRadius = size.height/2) : (thumbLayer.cornerRadius = thumbCornerRadius)
308 | }
309 |
310 | private func layoutOffContentLayer(for bounds: CGRect) {
311 | let size = getContentLayerSize(for: offContentLayer)
312 | let y = bounds.midY - size.height/2
313 | let leading = (bounds.maxX - (contentLeadingTrailingPadding + borderWidth + getThumbSize().width))/2 - size.width/2
314 | let x = !isOn ? bounds.width - size.width - leading : bounds.width
315 | let origin = CGPoint(x: x, y: y)
316 | offContentLayer?.frame = CGRect(origin: origin, size: size)
317 | bounds.height < 50 ? ((offContentLayer as? CATextLayer)?.fontSize = 12) : ((offContentLayer as? CATextLayer)?.fontSize = bounds.height * 0.2)
318 | }
319 |
320 | private func layoutOnContentLayer(for bounds: CGRect) {
321 | let size = getContentLayerSize(for: onContentLayer)
322 | let y = bounds.midY - size.height/2
323 | let leading = (bounds.maxX - (contentLeadingTrailingPadding + borderWidth + getThumbSize().width))/2 - size.width/2
324 | let x = isOn ? leading : -bounds.width/2
325 | let origin = CGPoint(x: x, y: y)
326 | onContentLayer?.frame = CGRect(origin: origin, size: size)
327 | onContentLayer?.contentsCenter = CGRect(origin: origin, size: size)
328 | bounds.height < 50 ? ((onContentLayer as? CATextLayer)?.fontSize = 12) : ((onContentLayer as? CATextLayer)?.fontSize = bounds.height * 0.2)
329 | }
330 |
331 | fileprivate func stateDidChange() {
332 | trackLayer.backgroundColor = getBackgroundColor()
333 | trackLayer.borderWidth = borderWidth
334 | thumbLayer.contents = isOn ? onThumbImage?.cgImage : offThumbImage?.cgImage
335 | setThumbColor()
336 | sendActions(for: .valueChanged)
337 | valueChange?(isOn)
338 | }
339 |
340 | public func setOn(_ on: Bool, animated: Bool) {
341 | CATransaction.begin()
342 | CATransaction.setDisableActions(!animated)
343 | isOn = on
344 | layoutSublayers(of: layer)
345 | sendActions(for: .valueChanged)
346 | valueChange?(isOn)
347 | CATransaction.commit()
348 | }
349 |
350 | // MARK: - Touches
351 |
352 | private func addTouchHandlers() {
353 | addTarget(self, action: #selector(touchDown), for: [.touchDown, .touchDragEnter])
354 | addTarget(self, action: #selector(touchUp), for: [.touchUpInside])
355 | addTarget(self, action: #selector(touchEnded), for: [.touchDragExit, .touchCancel])
356 |
357 | let leftSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
358 | leftSwipeGesture.direction = [.left]
359 | addGestureRecognizer(leftSwipeGesture)
360 |
361 | let rightSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeLeftRight(_:)))
362 | rightSwipeGesture.direction = [.right]
363 | addGestureRecognizer(rightSwipeGesture)
364 | }
365 |
366 | @objc
367 | private func swipeLeftRight(_ gesture: UISwipeGestureRecognizer) {
368 | let canLeftSwipe = isOn && gesture.direction == .left
369 | let canRightSwipe = !isOn && gesture.direction == .right
370 | guard canLeftSwipe || canRightSwipe else { return }
371 | touchUp()
372 | }
373 |
374 | @objc
375 | fileprivate func touchDown() {
376 | print("touch down")
377 | isTouchDown = true
378 | layoutSublayers(of: layer)
379 | }
380 |
381 | @objc
382 | fileprivate func touchUp() {
383 | isOn.toggle()
384 | stateDidChange()
385 | touchEnded()
386 | }
387 |
388 | @objc
389 | fileprivate func touchEnded() {
390 | isTouchDown = false
391 | layoutSublayers(of: layer)
392 | }
393 |
394 | // MARK: - Layout Helper
395 |
396 | fileprivate func setBorderColor() {
397 | if let borderClor = borderColor {
398 | trackLayer.borderColor = borderClor.cgColor
399 | } else {
400 | trackLayer.borderColor = (isOn ? onBorderColor : offBorderColor).cgColor
401 | }
402 | }
403 |
404 | private func setThumbColor() {
405 | if let thumbColor = thumbTintColor {
406 | thumbLayer.backgroundColor = thumbColor.cgColor
407 | } else {
408 | thumbLayer.backgroundColor = (isOn ? onThumbTintColor : offThumbTintColor).cgColor
409 | }
410 | }
411 |
412 | final func getBackgroundColor() -> CGColor {
413 | return (isOn ? onTintColor : offTintColor).cgColor
414 | }
415 |
416 | fileprivate func getThumbSize() -> CGSize {
417 | let height = bounds.height - 2 * (borderWidth + thumbRadiusPadding)
418 | let width = (isTouchDown && isStretchEnable) ? height * 1.2 : height
419 | return CGSize(width: width, height: height)
420 | }
421 |
422 | final func getThumbOrigin(for width: CGFloat) -> CGPoint {
423 | let inset = borderWidth + thumbRadiusPadding
424 | let x = isOn ? bounds.width - width - inset : inset
425 | return CGPoint(x: x, y: inset)
426 | }
427 |
428 | final func getContentLayerSize(for layer: CALayer?) -> CGSize {
429 | let inset = 2 * (borderWidth + trackTopBottomPadding)
430 | let diameter = bounds.height - inset - getThumbSize().height/2
431 | if let textLayer = layer as? CATextLayer {
432 | return textLayer.preferredFrameSize()
433 | }
434 | return CGSize(width: diameter, height: diameter)
435 | }
436 |
437 | // MARK: - Content Layers
438 |
439 | private func addOffTextLayerIfNeeded() {
440 | guard offText != nil else {
441 | offContentLayer = nil
442 | return
443 | }
444 | let textLayer = CATextLayer()
445 | textLayer.alignmentMode = .center
446 | textLayer.fontSize = bounds.height * 0.2
447 | textLayer.font = UIFont.systemFont(ofSize: 10, weight: .bold)
448 |
449 | textLayer.foregroundColor = (textColor == nil) ? offTextColor.cgColor : textColor?.cgColor
450 | textLayer.contentsScale = UIScreen.main.scale
451 | contentsLayer.addSublayer(textLayer)
452 | offContentLayer = textLayer
453 | }
454 |
455 | private func addOnTextLayerIfNeeded() {
456 | guard onText != nil else {
457 | onContentLayer = nil
458 | return
459 | }
460 | let textLayer = CATextLayer()
461 | textLayer.alignmentMode = .center
462 | textLayer.fontSize = bounds.height * 0.2
463 | textLayer.font = UIFont.systemFont(ofSize: 10, weight: .bold)
464 | textLayer.foregroundColor = (textColor == nil) ? onTextColor.cgColor : textColor?.cgColor
465 | textLayer.contentsScale = UIScreen.main.scale
466 | contentsLayer.addSublayer(textLayer)
467 | onContentLayer = textLayer
468 | }
469 |
470 | private func addOnImageLayerIfNeeded() {
471 | guard onImage != nil else {
472 | onContentLayer = nil
473 | return
474 | }
475 | let imageLayer = CALayer()
476 | imageLayer.contentsGravity = .center
477 | imageLayer.contentsScale = UIScreen.main.scale
478 | contentsLayer.addSublayer(imageLayer)
479 | onContentLayer = imageLayer
480 | }
481 |
482 | private func addOffImageLayerIfNeeded() {
483 | guard offImage != nil else {
484 | offContentLayer = nil
485 | return
486 | }
487 | let imageLayer = CALayer()
488 | imageLayer.contentsGravity = .resizeAspect
489 | imageLayer.contentsScale = UIScreen.main.scale
490 | contentsLayer.addSublayer(imageLayer)
491 | offContentLayer = imageLayer
492 | }
493 | }
494 |
495 | // https://dribbble.com/shots/2158763-simple-toggle
496 | @IBDesignable public class YapSwitchSlim: YapSwitch {
497 | public var slimTrack: CGFloat = 0 {
498 | didSet {
499 | layoutSublayers(of: layer)
500 | }
501 | }
502 |
503 | override func layoutTrackLayer(for bounds: CGRect) {
504 | trackLayer.frame = bounds.insetBy(dx: trackTopBottomPadding, dy: trackTopBottomPadding + slimTrack)
505 | shape == .rounded ? (trackLayer.cornerRadius = trackLayer.bounds.height/2) : (trackLayer.cornerRadius = bounds.height * 0.2)
506 | }
507 |
508 | override func layoutInnerLayer(for bounds: CGRect) {
509 | let inset = borderWidth + trackTopBottomPadding
510 | let isInnerHidden = isOn || (isTouchDown && isStretchEnable)
511 |
512 | innerLayer.frame = isInnerHidden
513 | ? CGRect(origin: trackLayer.position, size: .zero)
514 | : trackLayer.frame.insetBy(dx: inset, dy: inset)
515 |
516 | shape == .rounded ? (innerLayer.cornerRadius = isInnerHidden ? 0 : innerLayer.bounds.height/2 - inset) : (innerLayer.cornerRadius = isInnerHidden ? 5 : 5)
517 | }
518 | }
519 |
520 | ////`Credit`: Robin
521 | // https://dribbble.com/shots/2603107-toggle-switch-micro-interaction
522 |
523 | // MARK: - YapGradientSwitch
524 |
525 | public enum GradientPosition {
526 | case vertical
527 | case horizatal
528 | }
529 |
530 | @IBDesignable public class YapGradientSwitch: YapSwitch {
531 | private lazy var onGradientLayer = CAGradientLayer()
532 | private lazy var offGradientLayer = CAGradientLayer()
533 |
534 | public var gradientPosition: GradientPosition = .horizatal {
535 | didSet {
536 | setGradientPosition()
537 | layoutSublayers(of: layer)
538 | }
539 | }
540 |
541 | public var onColors: [UIColor] = [UIColor.red, UIColor.yellow] {
542 | didSet {
543 | onGradientLayer.colors = onColors.map { $0.cgColor }
544 | }
545 | }
546 |
547 | public var offColors: [UIColor] = [UIColor.red, UIColor.yellow] {
548 | didSet {
549 | offGradientLayer.colors = offColors.map { $0.cgColor }
550 | }
551 | }
552 |
553 | func createGradientLayer() {
554 | trackLayer.addSublayer(onGradientLayer)
555 | innerLayer.addSublayer(offGradientLayer)
556 | setGradientPosition()
557 | }
558 |
559 | private func setGradientPosition() {
560 | if gradientPosition == .horizatal {
561 | onGradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
562 | onGradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
563 |
564 | offGradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
565 | offGradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
566 | } else {
567 | onGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
568 | onGradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
569 |
570 | offGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
571 | offGradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
572 | }
573 | }
574 |
575 | override func controlDidLoad() {
576 | super.controlDidLoad()
577 | createGradientLayer()
578 | }
579 |
580 | override public func layoutSublayers(of layer: CALayer) {
581 | super.layoutSublayers(of: layer)
582 | layoutInnerLayer(for: bounds)
583 |
584 | onGradientLayer.frame = trackLayer.bounds
585 | offGradientLayer.frame = trackLayer.bounds
586 |
587 | innerLayer.masksToBounds = true
588 |
589 | onGradientLayer.cornerRadius = trackLayer.cornerRadius
590 | offGradientLayer.cornerRadius = innerLayer.cornerRadius
591 | }
592 | }
593 |
594 | private protocol AnimationPath {
595 | func drawOnPath(_ group: CGRect) -> CGPath
596 | func drawOffPath(_ group: CGRect) -> CGPath
597 | }
598 |
599 | //// `Credit Design` : Andrei Mironov
600 | // https://dribbble.com/shots/2309834-Yet-another-toggle-animation
601 |
602 | // MARK: - YapAnimatedSwitch
603 |
604 | @IBDesignable public class YapAnimatedSwitch: YapSwitch {
605 | public var animationColor: UIColor? {
606 | didSet { setShapeColor() }
607 | }
608 |
609 | public var onAnimationColor: UIColor = .white {
610 | didSet { setShapeColor() }
611 | }
612 |
613 | public var offAnimationColor: UIColor = .white {
614 | didSet { setShapeColor() }
615 | }
616 |
617 | public var animationWidth: CGFloat = 3 {
618 | didSet { shapeLayer.lineWidth = animationWidth }
619 | }
620 |
621 | private lazy var shapeLayer: CAShapeLayer = {
622 | let shape = CAShapeLayer()
623 | shape.fillColor = UIColor.clear.cgColor
624 | shape.lineCap = .round
625 | shape.lineWidth = animationWidth
626 | return shape
627 | }()
628 |
629 | public let duration: Double = 0.6
630 |
631 | override func controlDidLoad() {
632 | super.controlDidLoad()
633 |
634 | isStretchEnable = false
635 | thumbLayer.addSublayer(shapeLayer)
636 | setShapeColor()
637 | DispatchQueue.main.async {
638 | self.layoutThumbLayer(for: self.bounds)
639 | self.shapeLayer.path = self.isOn ? self.thumbLayer.bounds.drawOnPath : self.thumbLayer.bounds.drawOffPath
640 | }
641 | }
642 |
643 | private func setShapeColor() {
644 | shapeLayer.strokeColor = (animationColor ?? (isOn ? onAnimationColor : offAnimationColor)).cgColor
645 | }
646 |
647 | override public func layoutSublayers(of layer: CALayer) {
648 | CATransaction.setAnimationDuration(duration)
649 | CATransaction.begin()
650 | super.layoutSublayers(of: layer)
651 | CATransaction.commit()
652 |
653 | shapeLayer.frame = thumbLayer.bounds
654 | }
655 |
656 | override func stateDidChange() {
657 | super.stateDidChange()
658 | isOn ? shapeLayer.animateShape(path: thumbLayer.bounds.drawOnPath, duration: duration - duration/2) : shapeLayer.animateShape(path: thumbLayer.bounds.drawOffPath, duration: duration - duration/2)
659 | isOn ? shapeLayer.rotateAnimation(angal: 0, duration: duration) : shapeLayer.rotateAnimation(angal: .pi/2, duration: duration)
660 | setShapeColor()
661 | }
662 | }
663 |
664 | /// `Design by` : tomatree
665 | // https://dribbble.com/shots/2484722-Daily-Ui-Day-15-On-Off-Switch
666 |
667 | // MARK: - YapModeSwitch
668 |
669 | @IBDesignable public class YapModeSwitch: YapSwitch {
670 | private lazy var shapeLayer: CAShapeLayer = {
671 | let shape = CAShapeLayer()
672 | shape.strokeColor = UIColor.clear.cgColor
673 |
674 | return shape
675 | }()
676 |
677 | private let duration: Double = 0.6
678 |
679 | override public func layoutSublayers(of layer: CALayer) {
680 | CATransaction.setAnimationDuration(duration)
681 | CATransaction.begin()
682 | super.layoutSublayers(of: layer)
683 | CATransaction.commit()
684 |
685 | shapeLayer.fillColor = thumbTintColor?.cgColor
686 | shapeLayer.frame = thumbLayer.bounds
687 | thumbLayer.backgroundColor = UIColor.clear.cgColor
688 | }
689 |
690 | override func controlDidLoad() {
691 | super.controlDidLoad()
692 |
693 | isStretchEnable = false
694 | thumbLayer.addSublayer(shapeLayer)
695 |
696 | DispatchQueue.main.async {
697 | self.shapeLayer.path = self.isOn ? self.thumbLayer.bounds.drawModeOffPath : self.thumbLayer.bounds.drawModeOnPath
698 | }
699 | }
700 |
701 | override func stateDidChange() {
702 | super.stateDidChange()
703 | isOn ? shapeLayer.animateShape(path: thumbLayer.bounds.drawModeOffPath, duration: duration - duration/1.5) : shapeLayer.animateShape(path: thumbLayer.bounds.drawModeOnPath, duration: duration - duration/1.5)
704 | }
705 | }
706 |
707 | @IBDesignable public class YapDarkAndLightModeSwitch: YapSwitch {
708 | public let duration: Double = 0.6
709 |
710 | private lazy var shapeLayer: CAShapeLayer = {
711 | let shape = CAShapeLayer()
712 | shape.strokeColor = UIColor.clear.cgColor
713 | return shape
714 | }()
715 |
716 | private lazy var maskLayer = CAShapeLayer()
717 |
718 | override public func layoutSublayers(of layer: CALayer) {
719 | CATransaction.setAnimationDuration(duration)
720 | CATransaction.begin()
721 | super.layoutSublayers(of: layer)
722 | CATransaction.commit()
723 |
724 | maskLayer.frame = thumbLayer.bounds
725 |
726 | shapeLayer.frame = thumbLayer.bounds
727 | shapeLayer.path = drawSunShape(thumbLayer.bounds)
728 | shapeLayer.mask = maskLayer
729 | thumbLayer.backgroundColor = thumbTintColor?.cgColor
730 | }
731 |
732 | override func controlDidLoad() {
733 | super.controlDidLoad()
734 |
735 | isStretchEnable = false
736 | thumbLayer.addSublayer(shapeLayer)
737 |
738 | DispatchQueue.main.async {
739 | self.isOn ? (self.maskLayer.path = self.drawOnPath(self.thumbLayer.bounds)) : (self.maskLayer.path = self.drawOffPath(self.thumbLayer.bounds))
740 | }
741 | thumbLayer.masksToBounds = true
742 | }
743 |
744 | override func stateDidChange() {
745 | super.stateDidChange()
746 | isOn ? maskLayer.animateShape(path: drawOnPath(thumbLayer.bounds), duration: duration) : maskLayer.animateShape(path: drawOffPath(thumbLayer.bounds), duration: duration)
747 |
748 | isOn ? thumbLayer.rotateAnimation(angal: 45.degreesToRadians, duration: duration) : thumbLayer.rotateAnimation(angal: 0, duration: duration)
749 |
750 | isOn ? animateFillColor(onTintColor) : animateFillColor(offTintColor)
751 | }
752 |
753 | private func animateFillColor(_ color: UIColor) {
754 | CATransaction.begin()
755 | CATransaction.setAnimationDuration(duration/2)
756 | shapeLayer.fillColor = color.cgColor
757 | CATransaction.commit()
758 | }
759 | }
760 |
761 | extension YapDarkAndLightModeSwitch: AnimationPath {
762 | private func drawSunShape(_ group: CGRect) -> CGPath {
763 | let bezierPath = UIBezierPath()
764 | let radius = group.maxX/2
765 | let center = CGPoint(x: group.midX, y: group.midY)
766 | bezierPath.addArc(withCenter: center, radius: radius, startAngle: -.pi/2, endAngle: 3 * .pi * 0.5, clockwise: true)
767 | return bezierPath.cgPath
768 | }
769 |
770 | func setMask(isFullSize: Bool) -> CGPath {
771 | var radius = thumbLayer.bounds.maxY/2
772 | let center = CGPoint(x: thumbLayer.bounds.midX, y: thumbLayer.bounds.midY)
773 |
774 | let x1 = center.x + radius * cos(180.degreesToRadians)
775 | let y1 = center.y + radius * sin(180.degreesToRadians)
776 |
777 | let bezierPath = UIBezierPath()
778 |
779 | isFullSize ? (radius = 0) : (radius += 0)
780 |
781 | bezierPath.addArc(withCenter: CGPoint(x: x1, y: y1), radius: radius, startAngle: -90.degreesToRadians, endAngle: 90.degreesToRadians, clockwise: true)
782 |
783 | return bezierPath.cgPath
784 | }
785 |
786 | func drawOnPath(_ group: CGRect) -> CGPath {
787 | return setMask(isFullSize: false)
788 | }
789 |
790 | func drawOffPath(_ group: CGRect) -> CGPath {
791 | return setMask(isFullSize: true)
792 | }
793 | }
794 |
795 | @IBDesignable public class YapFullStretchSwitch: YapSwitch {
796 | override func getThumbSize() -> CGSize {
797 | let height = bounds.height - 2 * (borderWidth + thumbRadiusPadding)
798 | let width = (isTouchDown && isStretchEnable) ? bounds.width - 2 * (borderWidth + thumbRadiusPadding) : height
799 | return CGSize(width: width, height: height)
800 | }
801 | }
802 |
803 | @IBDesignable public class YapHalfStretchSwitch: YapSwitch {
804 | override func getThumbSize() -> CGSize {
805 | let height = bounds.height - 2 * (borderWidth + thumbRadiusPadding)
806 | let width = (isTouchDown && isStretchEnable) ? bounds.midX + bounds.midX/2 - 2 * (borderWidth + thumbRadiusPadding) : height
807 | return CGSize(width: width, height: height)
808 | }
809 |
810 | override public func layoutSublayers(of layer: CALayer) {
811 | super.layoutSublayers(of: layer)
812 | if shape == .square {
813 | thumbLayer.cornerRadius = bounds.height * 0.1
814 | thumbLayer.shadowOffset = .zero
815 | }
816 | }
817 | }
818 |
--------------------------------------------------------------------------------
/Switches.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "Switches"
4 | s.version = "3.0.0"
5 | s.summary = "Switches framework"
6 | s.description = <<-DESC
7 | Switches Pod can create number of beautiful customised switch confirming from UIControl with awesome animations
8 | DESC
9 | s.homepage = "https://github.com/jwd-ali/IOS-Portfolio"
10 | s.license = "MIT"
11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
12 | s.authors = { "Jawad Ali" => "L060214@gmail.com" }
13 | s.platforms = { :ios => "9.0" }
14 | s.source = { :git => "https://github.com/jwd-ali/Switches.git", :tag => "#{s.version}" }
15 |
16 | s.source_files = "Sources/**/*.{h,m,swift}"
17 | s.swift_version = "5.0"
18 | end
19 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/xcshareddata/xcschemes/Switches.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/xcshareddata/xcschemes/SwitchesDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/xcuserdata/jawadali.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/Switches.xcodeproj/xcuserdata/jawadali.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Switches.xcscheme_^#shared#^_
8 |
9 | isShown
10 |
11 | orderHint
12 | 1
13 |
14 | SwitchesDemo.xcscheme_^#shared#^_
15 |
16 | isShown
17 |
18 | orderHint
19 | 0
20 |
21 |
22 | SuppressBuildableAutocreation
23 |
24 | E30C48B024FAE6930049D5C3
25 |
26 | primary
27 |
28 |
29 | E30C48B924FAE6930049D5C3
30 |
31 | primary
32 |
33 |
34 | E30C48E824FAE73F0049D5C3
35 |
36 | primary
37 |
38 |
39 | E30C48FD24FAE7420049D5C3
40 |
41 | primary
42 |
43 |
44 | E30C490824FAE7420049D5C3
45 |
46 | primary
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/SwitchesDemo/Application/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 11/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/SwitchesDemo/Application/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 11/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/AnimatedSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AimatedSwitchedViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 21/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class AnimatedSwitchesViewController: UIViewController {
12 |
13 | @IBOutlet weak var animatedStyleA: YapAnimatedSwitch! {
14 | didSet {
15 | animatedStyleA.thumbRadiusPadding = 6
16 | animatedStyleA.offThumbTintColor = #colorLiteral(red: 0.9540559649, green: 0.8972979188, blue: 0.8275271654, alpha: 1)
17 | animatedStyleA.onThumbTintColor = #colorLiteral(red: 0.4935741425, green: 0.5258994699, blue: 0.9827957749, alpha: 1)
18 | animatedStyleA.onTintColor = .white
19 | animatedStyleA.offTintColor = .white
20 | animatedStyleA.tintColor = .white
21 | }
22 | }
23 | @IBOutlet weak var animatedStyleB: YapAnimatedSwitch! {
24 | didSet {
25 | animatedStyleB.thumbRadiusPadding = 6
26 | animatedStyleB.thumbTintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
27 | animatedStyleB.animationWidth = 5
28 | animatedStyleB.onTintColor = #colorLiteral(red: 0.2841374278, green: 0.651584208, blue: 0.2687274218, alpha: 1)
29 | animatedStyleB.isOn = true
30 | animatedStyleB.offTintColor = #colorLiteral(red: 0.1686089635, green: 0.1686392426, blue: 0.1686022878, alpha: 1)
31 | animatedStyleB.onAnimationColor = #colorLiteral(red: 0.2841374278, green: 0.651584208, blue: 0.2687274218, alpha: 1)
32 | animatedStyleB.offAnimationColor = #colorLiteral(red: 0.1686089635, green: 0.1686392426, blue: 0.1686022878, alpha: 1)
33 | }
34 | }
35 | override func viewDidLoad() {
36 | title = "Animated Switches"
37 | super.viewDidLoad()
38 |
39 | // Do any additional setup after loading the view.
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/CollectionViewCell/CollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionViewCell.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 27/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class CollectionViewCell: UICollectionViewCell {
12 |
13 | private var switchv : BaseControl! {
14 | didSet{
15 | switchv.translatesAutoresizingMaskIntoConstraints = false
16 | }
17 | }
18 |
19 | //MARK: binding with controller to perform segue
20 |
21 | var performSgue : ((_ segue:String)-> Void)?
22 |
23 | @IBOutlet weak var displaySwitch: UIView! {
24 | didSet {
25 | displaySwitch.layer.shadowOffset = .zero
26 | displaySwitch.layer.shadowOpacity = 0.15
27 | displaySwitch.layer.shadowRadius = 7
28 | displaySwitch.layer.cornerRadius = 10
29 | }
30 | }
31 |
32 | @IBOutlet weak var collectionName: UILabel!
33 | @IBOutlet weak var viewAllButton: UIButton!
34 | @IBOutlet weak var holdingView: UIView! {
35 | didSet {
36 | holdingView.layer.shadowOffset = .zero
37 | holdingView.layer.shadowOpacity = 0.15
38 | holdingView.layer.shadowRadius = 7
39 | holdingView.layer.cornerRadius = 10
40 | }
41 | }
42 |
43 | private var type : SwitchType!
44 |
45 | override func awakeFromNib() {
46 | super.awakeFromNib()
47 | }
48 |
49 | override func layoutSubviews() {
50 | super.layoutSubviews()
51 | viewAllButton.layer.cornerRadius = viewAllButton.bounds.midY
52 | }
53 |
54 | @IBAction func viewAllTapped(_ sender: UIButton) {
55 |
56 | performSgue?(type.rawValue)
57 |
58 | }
59 |
60 |
61 | func config(type: SwitchType) {
62 | self.type = type
63 | collectionName.text = type.rawValue
64 |
65 | switchv = type.coverSwitch
66 | displaySwitch.addSubview(switchv)
67 |
68 | if type == SwitchType.loading {
69 | (self.switchv as? SDSwitch)?.loadingStarted = {
70 | DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
71 |
72 | (self.switchv as? SDSwitch)?.loadingCompleted(isSuccessFull: true)
73 | }
74 | }
75 |
76 | }
77 |
78 | switchv.topAnchor.constraint(equalTo: displaySwitch.topAnchor).isActive = true
79 | switchv.bottomAnchor.constraint(equalTo: displaySwitch.bottomAnchor).isActive = true
80 | switchv.leadingAnchor.constraint(equalTo: displaySwitch.leadingAnchor).isActive = true
81 | switchv.trailingAnchor.constraint(equalTo: displaySwitch.trailingAnchor).isActive = true
82 |
83 | switchv.addTarget(self, action: #selector(changedSwitchVal), for: .valueChanged)
84 |
85 | }
86 |
87 | @objc func changedSwitchVal(_ sender: BaseControl) {
88 | print(sender.isOn)
89 |
90 | }
91 |
92 | override func prepareForReuse() {
93 | super.prepareForReuse()
94 |
95 | switchv.removeFromSuperview()
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/GradientSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GradientSwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 23/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class GradientSwitchesViewController: UIViewController {
12 |
13 | private lazy var gradientLayerVertical = CAGradientLayer()
14 | private lazy var gradientLayerHorizantal = CAGradientLayer()
15 |
16 | @IBOutlet weak var gradientSwitchHorizantal: YapGradientSwitch! {
17 | didSet {
18 | gradientSwitchHorizantal.gradientPosition = .horizatal
19 | gradientSwitchHorizantal.onColors = [#colorLiteral(red: 0.2394029498, green: 0.8576775193, blue: 0.6665194631, alpha: 1),#colorLiteral(red: 0.04418379813, green: 0.5335158706, blue: 0.5292400718, alpha: 1)]
20 | gradientSwitchHorizantal.offColors = [#colorLiteral(red: 0.1861540377, green: 0.2199867666, blue: 0.2542595267, alpha: 1),#colorLiteral(red: 0.1861540377, green: 0.2199867666, blue: 0.2542595267, alpha: 1)]
21 |
22 | gradientSwitchHorizantal.onText = "ON"
23 | gradientSwitchHorizantal.offText = "OFF"
24 | }
25 | }
26 | @IBOutlet weak var gradientSwitchVertical: YapGradientSwitch!{
27 | didSet {
28 | gradientSwitchVertical.borderWidth = 2
29 | gradientSwitchVertical.gradientPosition = .vertical
30 | gradientSwitchVertical.onColors = [#colorLiteral(red: 0.722638309, green: 0.1586903036, blue: 0.2223222256, alpha: 1),#colorLiteral(red: 0.1921568662, green: 0.007843137719, blue: 0.09019608051, alpha: 1)]
31 | gradientSwitchVertical.offColors = [#colorLiteral(red: 0.1042157337, green: 0.4639918208, blue: 0.2866171598, alpha: 1),#colorLiteral(red: 0.1294117719, green: 0.1414276541, blue: 0.06666667014, alpha: 1)]
32 |
33 | gradientSwitchVertical.onText = "START"
34 | gradientSwitchVertical.offText = "STOP"
35 | }
36 | }
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 |
40 | gradientSwitchVertical.superview?.layer.insertSublayer(gradientLayerVertical, at: 0)
41 | gradientLayerVertical.colors = gradientSwitchVertical.offColors.map{$0.withAlphaComponent(0.7).cgColor}
42 |
43 | gradientSwitchHorizantal.superview?.layer.insertSublayer(gradientLayerHorizantal, at: 0)
44 | gradientLayerHorizantal.colors = gradientSwitchHorizantal.offColors.map{$0.withAlphaComponent(0.3).cgColor}
45 |
46 | gradientSwitchVertical.addTarget(self, action: #selector(switchVerticalToggle(_:)), for: .valueChanged)
47 | gradientSwitchHorizantal.addTarget(self, action: #selector(switchHorizantalToggle(_:)), for: .valueChanged)
48 |
49 | title = "Gradient Switches"
50 |
51 |
52 | // Do any additional setup after loading the view.
53 | }
54 |
55 |
56 |
57 | override func viewDidLayoutSubviews() {
58 | gradientLayerVertical.frame = gradientSwitchVertical.superview?.bounds ?? .zero
59 | gradientLayerHorizantal.frame = gradientSwitchHorizantal.superview?.bounds ?? .zero
60 | }
61 |
62 | @objc func switchVerticalToggle(_ sender: YapDarkAndLightModeSwitch) {
63 |
64 | sender.isOn ? gradientLayerVertical.animateGradientColors(from: gradientSwitchVertical.offColors.map{$0.withAlphaComponent(0.7).cgColor}, to: gradientSwitchVertical.onColors.map{$0.withAlphaComponent(0.7).cgColor}, duration: 0.5) : gradientLayerVertical.animateGradientColors(from: gradientSwitchVertical.onColors.map{$0.withAlphaComponent(0.7).cgColor}, to: gradientSwitchVertical.offColors.map{$0.withAlphaComponent(0.7).cgColor}, duration: 0.5)
65 |
66 |
67 |
68 | }
69 | @objc func switchHorizantalToggle(_ sender: YapDarkAndLightModeSwitch) {
70 |
71 | sender.isOn ? gradientLayerHorizantal.animateGradientColors(from: gradientSwitchHorizantal.offColors.map{$0.withAlphaComponent(0.3).cgColor}, to: gradientSwitchHorizantal.onColors.map{$0.withAlphaComponent(0.3).cgColor}, duration: 0.5) : gradientLayerHorizantal.animateGradientColors(from: gradientSwitchHorizantal.onColors.map{$0.withAlphaComponent(0.3).cgColor}, to: gradientSwitchHorizantal.offColors.map{$0.withAlphaComponent(0.3).cgColor}, duration: 0.5)
72 |
73 |
74 |
75 | }
76 |
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/JellySwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JellySwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 24/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class JellySwitchesViewController: UIViewController {
12 |
13 | @IBOutlet weak var fullStretchSwitch: YapFullStretchSwitch! {
14 | didSet {
15 | fullStretchSwitch.onThumbImage = UIImage(named: "check")
16 | fullStretchSwitch.thumbRadiusPadding = 0
17 | fullStretchSwitch.borderColor = #colorLiteral(red: 0.7999292612, green: 0.8000453115, blue: 0.7999040484, alpha: 1)
18 | fullStretchSwitch.borderWidth = 3
19 | fullStretchSwitch.onTintColor = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
20 | fullStretchSwitch.offTintColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
21 | }
22 | }
23 | @IBOutlet weak var halfStretchSwitch: YapHalfStretchSwitch! {
24 | didSet {
25 |
26 | halfStretchSwitch.shape = .square
27 | halfStretchSwitch.thumbRadiusPadding = 4
28 | halfStretchSwitch.borderColor = #colorLiteral(red: 0.7999292612, green: 0.8000453115, blue: 0.7999040484, alpha: 1)
29 | halfStretchSwitch.borderWidth = 2
30 | halfStretchSwitch.onTintColor = #colorLiteral(red: 0.999904573, green: 1, blue: 0.9998808503, alpha: 1)
31 | halfStretchSwitch.offTintColor = #colorLiteral(red: 0.345902741, green: 0.7542000413, blue: 0.4488890171, alpha: 1)
32 |
33 | }
34 | }
35 | @IBOutlet weak var jellySwitch: YapLiquidSwitch!
36 |
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 | title = "Jelly Switch"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/LoadingSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingSwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 23/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class LoadingSwitchesViewController: UIViewController {
12 | @IBOutlet weak var loadingSwitch: SDSwitch! {
13 | didSet{
14 | loadingSwitch.isLoadingEnabled = true
15 | loadingSwitch.thumbRadiusPadding = 10
16 | }
17 | }
18 | var count = 0
19 | @IBOutlet weak var followedMiddleSwitch: SDSwitch! {
20 | didSet {
21 | followedMiddleSwitch.offBorderColor = #colorLiteral(red: 0.3974077106, green: 0.6517546177, blue: 0.9074617624, alpha: 1)
22 | followedMiddleSwitch.offThumbTintColor = #colorLiteral(red: 0.3974077106, green: 0.6517546177, blue: 0.9074617624, alpha: 1)
23 | followedMiddleSwitch.borderWidth = 4
24 | followedMiddleSwitch.thumbRadiusPadding = 8
25 | followedMiddleSwitch.onThumbTintColor = #colorLiteral(red: 0.6347479224, green: 0.50891155, blue: 0.9531157613, alpha: 1)
26 | followedMiddleSwitch.onBorderColor = #colorLiteral(red: 0.6347479224, green: 0.50891155, blue: 0.9531157613, alpha: 1)
27 | followedMiddleSwitch.onTintColor = .white
28 | followedMiddleSwitch.offTintColor = .white
29 | }
30 | }
31 | @IBOutlet weak var followedLastSwitch: YapFullTextSwitch! {
32 | didSet{
33 | followedLastSwitch.onTextColor = #colorLiteral(red: 0.2766842842, green: 0.8682026267, blue: 0.9832950234, alpha: 1)
34 | followedLastSwitch.offTextColor = #colorLiteral(red: 0.7480503321, green: 0.7532240748, blue: 0.7486134171, alpha: 1)
35 | followedLastSwitch.onText = "ON"
36 | followedLastSwitch.offText = "OFF"
37 | followedLastSwitch.onBorderColor = #colorLiteral(red: 0.2766842842, green: 0.8682026267, blue: 0.9832950234, alpha: 1)
38 | followedLastSwitch.offBorderColor = #colorLiteral(red: 0.9433093667, green: 0.9533157945, blue: 0.9529805779, alpha: 1)
39 | followedLastSwitch.onTintColor = #colorLiteral(red: 0.3614792228, green: 0.9322348237, blue: 0.9953452945, alpha: 1)
40 | followedLastSwitch.offTintColor = #colorLiteral(red: 0.948936522, green: 0.9490728974, blue: 0.9489069581, alpha: 1)
41 | followedLastSwitch.borderWidth = 5
42 | }
43 | }
44 |
45 | override func viewDidLoad() {
46 | super.viewDidLoad()
47 |
48 | title = "Loading Switches"
49 |
50 | loadingSwitch.loadingStarted = {
51 | DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
52 | (self.count % 2 == 0) ? self.loadingSwitch.loadingCompleted(isSuccessFull: true) : self.loadingSwitch.loadingCompleted(isSuccessFull: false)
53 | self.count += 1
54 | }
55 | }
56 | }
57 |
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/ModeBSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModeBSwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 22/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class ModeBSwitchesViewController: UIViewController {
12 |
13 | @IBOutlet weak var modeSwitchStyleA: YapModeSwitch! {
14 | didSet {
15 | modeSwitchStyleA.thumbRadiusPadding = 8
16 | modeSwitchStyleA.thumbTintColor = #colorLiteral(red: 0.9683158994, green: 0.501380682, blue: 0.4961987734, alpha: 1)
17 | modeSwitchStyleA.offTintColor = .white
18 | modeSwitchStyleA.onTintColor = #colorLiteral(red: 0.6057969332, green: 0.6360527277, blue: 0.9815277457, alpha: 1)
19 | }
20 | }
21 | @IBOutlet weak var modeSwitchStyleB: YapModeSwitch! {
22 | didSet {
23 | modeSwitchStyleB.thumbRadiusPadding = 8
24 | modeSwitchStyleB.thumbTintColor = .white
25 | modeSwitchStyleB.offTintColor = #colorLiteral(red: 0.2786044478, green: 0.5705410242, blue: 0.9243882298, alpha: 1)
26 | modeSwitchStyleB.onTintColor = #colorLiteral(red: 0.3037858903, green: 0.1899323463, blue: 0.6803773642, alpha: 1)
27 | }
28 | }
29 | override func viewDidLoad() {
30 |
31 | super.viewDidLoad()
32 | modeSwitchStyleB.addTarget(self, action: #selector(switchBToggle(_:)), for: .valueChanged)
33 |
34 | title = "Dark Light A Mode"
35 | }
36 |
37 |
38 | @objc func switchBToggle(_ sender: YapDarkAndLightModeSwitch) {
39 |
40 | let color = sender.isOn ? #colorLiteral(red: 0.5881829262, green: 0.4660730958, blue: 0.9921956658, alpha: 1) : .white
41 |
42 | UIView.animate(withDuration: sender.duration) {
43 | self.modeSwitchStyleB.superview?.backgroundColor = color
44 | }
45 |
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/ModeSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModeSwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 22/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class ModeSwitchesViewController: UIViewController {
12 |
13 | @IBOutlet weak var modeSwitchStyleA: YapDarkAndLightModeSwitch! {
14 | didSet {
15 | modeSwitchStyleA.thumbRadiusPadding = 8
16 | modeSwitchStyleA.thumbTintColor = #colorLiteral(red: 0.9683158994, green: 0.501380682, blue: 0.4961987734, alpha: 1)
17 | modeSwitchStyleA.offTintColor = .white
18 | modeSwitchStyleA.onTintColor = #colorLiteral(red: 0.6057969332, green: 0.6360527277, blue: 0.9815277457, alpha: 1)
19 | }
20 | }
21 | @IBOutlet weak var modeSwitchStyleB: YapDarkAndLightModeSwitch! {
22 | didSet {
23 | modeSwitchStyleB.thumbRadiusPadding = 8
24 | modeSwitchStyleB.thumbTintColor = .white
25 | modeSwitchStyleB.offTintColor = #colorLiteral(red: 0.2786044478, green: 0.5705410242, blue: 0.9243882298, alpha: 1)
26 | modeSwitchStyleB.onTintColor = #colorLiteral(red: 0.3037858903, green: 0.1899323463, blue: 0.6803773642, alpha: 1)
27 | }
28 | }
29 | override func viewDidLoad() {
30 |
31 | super.viewDidLoad()
32 | modeSwitchStyleB.addTarget(self, action: #selector(switchBToggle(_:)), for: .valueChanged)
33 |
34 | title = "Dark Light B Mode"
35 | }
36 |
37 |
38 | @objc func switchBToggle(_ sender: YapDarkAndLightModeSwitch) {
39 |
40 | let color = sender.isOn ? #colorLiteral(red: 0.5881829262, green: 0.4660730958, blue: 0.9921956658, alpha: 1) : .white
41 |
42 | UIView.animate(withDuration: sender.duration) {
43 | self.modeSwitchStyleB.superview?.backgroundColor = color
44 | }
45 |
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/RandomViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RandomViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 25/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class RandomViewController: UIViewController {
12 | @IBOutlet weak var randomA: YapSwitch! {
13 | didSet {
14 | randomA.onText = "ON"
15 | randomA.offText = "OFF"
16 | randomA.onTextColor = .white
17 | randomA.offTextColor = #colorLiteral(red: 0.2125092149, green: 0.2516930103, blue: 0.2772026062, alpha: 1)
18 | randomA.borderColor = #colorLiteral(red: 0.2125092149, green: 0.2516930103, blue: 0.2772026062, alpha: 1)
19 | randomA.onTintColor = #colorLiteral(red: 0.2125092149, green: 0.2516930103, blue: 0.2772026062, alpha: 1)
20 |
21 | randomA.offTextColor = #colorLiteral(red: 0.2125092149, green: 0.2516930103, blue: 0.2772026062, alpha: 1)
22 | randomA.offTintColor = .white
23 | randomA.offThumbTintColor = #colorLiteral(red: 0.2125092149, green: 0.2516930103, blue: 0.2772026062, alpha: 1)
24 | randomA.borderWidth = 2
25 | }
26 | }
27 | @IBOutlet weak var randomB: YapSwitchSlim! {
28 | didSet {
29 | randomB.onThumbTintColor = #colorLiteral(red: 0.0864540413, green: 0.5291488171, blue: 0.5380262733, alpha: 1)
30 | randomB.onTintColor = #colorLiteral(red: 0.4112847149, green: 0.7173692584, blue: 0.7089804411, alpha: 1)
31 | randomB.offTintColor = #colorLiteral(red: 0.5372059941, green: 0.5372863412, blue: 0.5371884108, alpha: 1)
32 | randomB.slimTrack = 10
33 | randomB.thumbRadiusPadding = 0
34 | }
35 | }
36 | @IBOutlet weak var randomC: YapSwitch! {
37 | didSet {
38 | randomC.onThumbImage = UIImage(named: "check")
39 | randomC.onTintColor = .purple
40 | randomC.offTintColor = #colorLiteral(red: 0.8552142978, green: 0.8781172037, blue: 0.9388162494, alpha: 1)
41 | }
42 | }
43 |
44 | @IBOutlet weak var randomD: YapSwitch! {
45 | didSet {
46 | randomD.onThumbTintColor = #colorLiteral(red: 0.1970949173, green: 0.799264133, blue: 0.8020008206, alpha: 1)
47 | randomD.onThumbImage = #imageLiteral(resourceName: "check").maskWithColor(color: .white)
48 | randomD.offThumbImage = #imageLiteral(resourceName: "close").maskWithColor(color: #colorLiteral(red: 0.170032382, green: 0.2437844872, blue: 0.3120466471, alpha: 1))
49 | randomD.offThumbTintColor = #colorLiteral(red: 0.8940391541, green: 0.8941679597, blue: 0.8940110803, alpha: 1)
50 | randomD.onTintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
51 | randomD.offTintColor = #colorLiteral(red: 0.170032382, green: 0.2437844872, blue: 0.3120466471, alpha: 1)
52 | }
53 | }
54 | @IBOutlet weak var randomE: YapSwitch! {
55 | didSet {
56 | randomE.onTextColor = #colorLiteral(red: 0.2311643958, green: 0.8008779883, blue: 0.6899323463, alpha: 1)
57 | randomE.offTextColor = #colorLiteral(red: 0.9092465753, green: 0.8114833048, blue: 0.810734161, alpha: 1)
58 | randomE.onThumbTintColor = #colorLiteral(red: 0.127592504, green: 0.7816838622, blue: 0.6617996693, alpha: 1)
59 | randomE.offThumbTintColor = #colorLiteral(red: 0.9092465753, green: 0.8114833048, blue: 0.810734161, alpha: 1)
60 | randomE.onText = "ON"
61 | randomE.offText = "OFF"
62 | randomE.onTintColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
63 | randomE.offTintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
64 | }
65 | }
66 |
67 |
68 | @IBOutlet weak var randomG: YapSwitch! {
69 | didSet {
70 | randomG.thumbTintColor = .yellow
71 | randomG.onText = "OFF"
72 | randomG.offText = "ON"
73 |
74 | randomG.onTintColor = .black
75 | randomG.borderWidth = 4
76 | randomG.textColor = .cyan
77 | randomG.offTintColor = .black
78 | randomG.onTextColor = .white
79 | }
80 | }
81 | @IBOutlet weak var randomH: YapSwitch! {
82 | didSet {
83 | randomH.onImage = UIImage(named: "icon_check_primary_dark")?.maskWithColor(color: .black)
84 | randomH.offImage = UIImage(named: "icon_close_dark_purple")?.maskWithColor(color: .red)
85 | randomH.shape = .square
86 | randomH.onTintColor = .yellow
87 | randomH.borderWidth = 5
88 | randomH.thumbCornerRadius = 0
89 | randomH.offTintColor = .green
90 | }
91 | }
92 | @IBOutlet weak var randomI: YapSwitch! {
93 | didSet {
94 | randomI.onThumbImage = UIImage(named: "check")
95 | randomI.offThumbImage = UIImage(named: "close")
96 | randomI.shape = .square
97 | randomI.onTintColor = .purple
98 | randomI.borderWidth = 2
99 | randomI.thumbCornerRadius = 0
100 | randomI.offTintColor = .red
101 | }
102 | }
103 |
104 |
105 | override func viewDidLoad() {
106 | super.viewDidLoad()
107 | title = "Random Switches"
108 | // Do any additional setup after loading the view.
109 | }
110 |
111 |
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/SmileyViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SmileyViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 25/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class SmileyViewController: UIViewController {
12 |
13 | @IBOutlet weak var randomA: YapSwitch! {
14 | didSet {
15 | randomA.thumbImage = UIImage(named: "thumb12")
16 | randomA.onTintColor = #colorLiteral(red: 0.8426451087, green: 0.3289524913, blue: 0.2659203112, alpha: 1)
17 | randomA.offTintColor = #colorLiteral(red: 0.7276904583, green: 0.7375378013, blue: 0.7416281104, alpha: 1)
18 | randomA.thumbTintColor = .clear
19 | randomA.onImage = #imageLiteral(resourceName: "check").maskWithColor(color: .white)
20 | randomA.offImage = UIImage(named: "cross7")
21 | randomA.shape = .square
22 | randomA.frame = CGRect(x: 200, y: 650, width: 65, height: 36)
23 | randomA.borderWidth = 2
24 | }
25 | }
26 | @IBOutlet weak var randomB: YapSwitch! {
27 | didSet {
28 | randomB.thumbImage = UIImage(named: "thumb1")
29 | randomB.onTintColor = #colorLiteral(red: 0.5955576897, green: 0.7103857398, blue: 0.2235306501, alpha: 1)
30 | randomB.layer.shadowOpacity = 0.6
31 | randomB.layer.shadowOffset = .zero
32 | randomB.layer.shadowRadius = 5
33 | randomB.layer.shadowColor = UIColor.black.cgColor
34 | randomB.onImage = #imageLiteral(resourceName: "check").maskWithColor(color: .white)
35 | randomB.offImage = UIImage(named: "off2")
36 | randomB.offTintColor = #colorLiteral(red: 0.7764018178, green: 0.7765145898, blue: 0.7763771415, alpha: 1)
37 | randomB.borderWidth = 1
38 | }
39 | }
40 | override func viewDidLoad() {
41 | super.viewDidLoad()
42 | title = "Smiley Switch"
43 | // Do any additional setup after loading the view.
44 | }
45 |
46 |
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/SwiftyViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 24/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class SwiftyViewController: UIViewController {
12 |
13 | @IBOutlet weak var swiftyA: Switcher! {
14 | didSet {
15 | swiftyA.superview?.layer.shadowOffset = .zero
16 | swiftyA.superview?.layer.shadowOpacity = 0.3
17 | swiftyA.superview?.layer.shadowRadius = 5
18 | }
19 | }
20 | @IBOutlet weak var swiftyB: Switcher! {
21 | didSet {
22 | swiftyB.superview?.layer.shadowOffset = .zero
23 | swiftyB.superview?.layer.shadowOpacity = 0.3
24 | swiftyB.superview?.layer.shadowRadius = 5
25 | }
26 | }
27 | @IBOutlet weak var swiftyC: JDSwitch! {
28 | didSet {
29 | swiftyC.thumbRadiusPadding = 8
30 | }
31 | }
32 | override func viewDidLoad() {
33 |
34 | title = "Stretchy Switch"
35 | super.viewDidLoad()
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/ThumbImageSwitchesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThumbImageSwitchesViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 24/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class ThumbImageSwitchesViewController: UIViewController {
12 |
13 | @IBOutlet weak var thumbImageSwitchD: YapSwitch! {
14 | didSet {
15 | thumbImageSwitchD.onThumbImage = UIImage(named: "go1")
16 | thumbImageSwitchD.offThumbImage = UIImage(named: "go2")
17 | thumbImageSwitchD.onTintColor = #colorLiteral(red: 0.6870710254, green: 0.2686487734, blue: 0.2165684998, alpha: 1)
18 | thumbImageSwitchD.offTintColor = #colorLiteral(red: 0.3156668544, green: 0.4091051519, blue: 0.481534183, alpha: 1)
19 | thumbImageSwitchD.thumbRadiusPadding = 8
20 | thumbImageSwitchD.isStretchEnable = false
21 | }
22 | }
23 | @IBOutlet weak var thumbImageSwitchC: YapSwitch! {
24 | didSet {
25 | thumbImageSwitchC.onThumbImage = #imageLiteral(resourceName: "right")
26 | thumbImageSwitchC.offThumbImage = #imageLiteral(resourceName: "left")
27 | thumbImageSwitchC.onTintColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
28 | thumbImageSwitchC.onText = "OFF"
29 | thumbImageSwitchC.offText = "ON"
30 | thumbImageSwitchC.offTextColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
31 | thumbImageSwitchC.offBorderColor = #colorLiteral(red: 0.8901180029, green: 0.8902462125, blue: 0.8900898695, alpha: 1)
32 | thumbImageSwitchC.onBorderColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
33 | thumbImageSwitchC.thumbRadiusPadding = 8
34 | thumbImageSwitchC.borderWidth = 3
35 | thumbImageSwitchC.offTintColor = #colorLiteral(red: 0.9568627451, green: 0.9587000478, blue: 0.9568627451, alpha: 1)
36 | }
37 | }
38 | @IBOutlet weak var thumbImageSwitchB: YapSwitch! {
39 | didSet {
40 | thumbImageSwitchB.onTextColor = #colorLiteral(red: 0.3056051731, green: 0.4627509713, blue: 0.01093915664, alpha: 1)
41 | thumbImageSwitchB.offTextColor = #colorLiteral(red: 0.5544068813, green: 0.08276418597, blue: 0.07942076772, alpha: 1)
42 | thumbImageSwitchB.thumbImage = UIImage(named: "thumb7")
43 | thumbImageSwitchB.thumbTintColor = .red
44 | thumbImageSwitchB.onText = "ON"
45 | thumbImageSwitchB.offText = "OFF"
46 | thumbImageSwitchB.thumbRadiusPadding = 1
47 | thumbImageSwitchB.thumbTintColor = .clear
48 | thumbImageSwitchB.borderWidth = 3
49 | thumbImageSwitchB.borderColor = #colorLiteral(red: 0.729346931, green: 0.7294533849, blue: 0.729323566, alpha: 1)
50 | thumbImageSwitchB.onTintColor = #colorLiteral(red: 0.6511958838, green: 0.8345313668, blue: 0.2781367004, alpha: 1)
51 | thumbImageSwitchB.offTintColor = #colorLiteral(red: 0.9100278616, green: 0.2768563628, blue: 0.2796021998, alpha: 1)
52 | }
53 | }
54 | @IBOutlet weak var thumbImageSwitchA: YapSwitchSlim! {
55 | didSet {
56 | thumbImageSwitchA.thumbImage = UIImage(named: "thumb4")
57 | thumbImageSwitchA.onText = "NO"
58 | thumbImageSwitchA.offText = "YES"
59 | thumbImageSwitchA.shape = .square
60 | thumbImageSwitchA.thumbRadiusPadding = 6
61 | thumbImageSwitchA.slimTrack = 5
62 | thumbImageSwitchA.thumbTintColor = .clear
63 | thumbImageSwitchA.borderWidth = 3
64 | thumbImageSwitchA.borderColor = #colorLiteral(red: 0.752874434, green: 0.7529839873, blue: 0.7528504729, alpha: 1)
65 | thumbImageSwitchA.onTintColor = #colorLiteral(red: 0.8561109304, green: 0.2607076168, blue: 0.5694340467, alpha: 1)
66 | thumbImageSwitchA.offTintColor = #colorLiteral(red: 0.09238574654, green: 0.4540643692, blue: 0.61872226, alpha: 1)
67 | thumbImageSwitchA.superview?.layer.shadowOffset = .zero
68 | thumbImageSwitchA.superview?.layer.shadowOpacity = 0.3
69 | thumbImageSwitchA.superview?.layer.shadowRadius = 5
70 | }
71 | }
72 | override func viewDidLoad() {
73 |
74 | // thumbImageSwitchA.valueChange = { [unowned self] isSuccess in
75 | // isSuccess ? (self.thumbImageSwitchA.superview?.superview?.backgroundColor = self.thumbImageSwitchA.onTintColor.withAlphaComponent(0.5)) : (self.thumbImageSwitchA.superview?.superview?.backgroundColor = self.thumbImageSwitchA.offTintColor.withAlphaComponent(0.5))
76 | // }
77 | title = "Thumb Image Switch"
78 |
79 | super.viewDidLoad()
80 |
81 | // Do any additional setup after loading the view.
82 | }
83 |
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/SwitchesDemo/Controllers/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 11/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | class ViewController: UIViewController {
12 | @IBOutlet weak var collectionView: UICollectionView!
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | title = "JD Switches"
17 | }
18 | }
19 |
20 | //MARK:- CollectionView Delegate
21 |
22 | extension UIViewController : UICollectionViewDelegate , UICollectionViewDataSource {
23 | public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
24 | return SwitchType.allCases.count
25 | }
26 |
27 | public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
28 |
29 |
30 | if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as? CollectionViewCell {
31 |
32 | let getCase = SwitchType.allCases[indexPath.row]
33 | cell.config(type: getCase)
34 |
35 | cell.performSgue = {[unowned self] identifier in
36 | self.performSegue(withIdentifier: identifier, sender: nil)
37 | }
38 | return cell
39 | }
40 |
41 | return UICollectionViewCell()
42 | }
43 | }
44 |
45 | //MARK:- Flow layout delegate
46 | extension UIViewController: UICollectionViewDelegateFlowLayout {
47 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
48 | let width = (view.bounds.width) / 2
49 | let height = width * 1.15
50 | return CGSize(width: width, height: height)
51 | }
52 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
53 | return 0
54 | }
55 |
56 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
57 | return 0
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/SwitchesDemo/Model/SwitchType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchType.swift
3 | // testi
4 | //
5 | // Created by Jawad Ali on 29/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Switches
11 | enum SwitchType:String, CaseIterable {
12 |
13 | case transition = "Transition Switches"
14 | case loading = "Loading Switches"
15 | case jelly = "Jelly Switches"
16 | case animated = "Animated Switches"
17 | case modeA = "Mode Switches"
18 | case modeB = "Cool Switches"
19 | case gradient = "Gradient Switches"
20 | case thumbImage = "Cover Switches"
21 | case smiley = "Smiley Switches"
22 | case ranndom = "Random Switches"
23 | }
24 | extension SwitchType {
25 |
26 | var coverSwitch: BaseControl {
27 | switch self {
28 | case .transition:
29 | let display = Switcher()
30 | display.superview?.layer.shadowOffset = .zero
31 | display.superview?.layer.shadowOpacity = 0.3
32 | display.superview?.layer.shadowRadius = 5
33 | return display
34 | case .loading:
35 | let display = SDSwitch()
36 | display.isLoadingEnabled = true
37 | display.thumbRadiusPadding = 5
38 | return display
39 | case .jelly:
40 | return YapLiquidSwitch()
41 | case .animated:
42 | let animatedStyleA = YapAnimatedSwitch()
43 | animatedStyleA.thumbRadiusPadding = 6
44 | animatedStyleA.offThumbTintColor = #colorLiteral(red: 0.9540559649, green: 0.8972979188, blue: 0.8275271654, alpha: 1)
45 | animatedStyleA.onThumbTintColor = #colorLiteral(red: 0.4935741425, green: 0.5258994699, blue: 0.9827957749, alpha: 1)
46 | animatedStyleA.onTintColor = .white
47 | animatedStyleA.offTintColor = .white
48 | animatedStyleA.tintColor = .white
49 | return animatedStyleA
50 | case .modeA:
51 | let modeSwitchStyleA = YapDarkAndLightModeSwitch()
52 | modeSwitchStyleA.thumbRadiusPadding = 8
53 | modeSwitchStyleA.thumbTintColor = #colorLiteral(red: 0.9683158994, green: 0.501380682, blue: 0.4961987734, alpha: 1)
54 | modeSwitchStyleA.offTintColor = .white
55 | modeSwitchStyleA.onTintColor = #colorLiteral(red: 0.6057969332, green: 0.6360527277, blue: 0.9815277457, alpha: 1)
56 | return modeSwitchStyleA
57 | case .modeB:
58 | let modeSwitchStyleA = YapModeSwitch()
59 | modeSwitchStyleA.thumbRadiusPadding = 8
60 | modeSwitchStyleA.thumbTintColor = #colorLiteral(red: 0.9683158994, green: 0.501380682, blue: 0.4961987734, alpha: 1)
61 | modeSwitchStyleA.offTintColor = .white
62 | modeSwitchStyleA.onTintColor = #colorLiteral(red: 0.6057969332, green: 0.6360527277, blue: 0.9815277457, alpha: 1)
63 | return modeSwitchStyleA
64 | case .gradient:
65 | let gradientSwitchVertical = YapGradientSwitch()
66 | gradientSwitchVertical.borderWidth = 2
67 | gradientSwitchVertical.gradientPosition = .vertical
68 | gradientSwitchVertical.onColors = [#colorLiteral(red: 0.722638309, green: 0.1586903036, blue: 0.2223222256, alpha: 1),#colorLiteral(red: 0.1921568662, green: 0.007843137719, blue: 0.09019608051, alpha: 1)]
69 | gradientSwitchVertical.offColors = [#colorLiteral(red: 0.1042157337, green: 0.4639918208, blue: 0.2866171598, alpha: 1),#colorLiteral(red: 0.1294117719, green: 0.1414276541, blue: 0.06666667014, alpha: 1)]
70 | gradientSwitchVertical.onText = "START"
71 | gradientSwitchVertical.offText = "STOP"
72 | return gradientSwitchVertical
73 |
74 | case .smiley:
75 | return YapSmileSwitch()
76 | case .thumbImage:
77 | let thumbImageSwitchC = YapSwitch()
78 | thumbImageSwitchC.onThumbImage = #imageLiteral(resourceName: "right")
79 | thumbImageSwitchC.offThumbImage = #imageLiteral(resourceName: "left")
80 | thumbImageSwitchC.onTintColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
81 | thumbImageSwitchC.onText = "OFF"
82 | thumbImageSwitchC.offText = "ON"
83 | thumbImageSwitchC.offTextColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
84 | thumbImageSwitchC.offBorderColor = #colorLiteral(red: 0.8901180029, green: 0.8902462125, blue: 0.8900898695, alpha: 1)
85 | thumbImageSwitchC.onBorderColor = #colorLiteral(red: 0.6210919023, green: 0.3142792583, blue: 0.6986252666, alpha: 1)
86 | thumbImageSwitchC.thumbRadiusPadding = 8
87 | thumbImageSwitchC.borderWidth = 3
88 | thumbImageSwitchC.offTintColor = #colorLiteral(red: 0.9568627451, green: 0.9587000478, blue: 0.9568627451, alpha: 1)
89 | return thumbImageSwitchC
90 | case .ranndom:
91 | let randomB = YapSwitchSlim()
92 |
93 | randomB.onThumbTintColor = #colorLiteral(red: 0.0864540413, green: 0.5291488171, blue: 0.5380262733, alpha: 1)
94 | randomB.onTintColor = #colorLiteral(red: 0.4112847149, green: 0.7173692584, blue: 0.7089804411, alpha: 1)
95 | randomB.offTintColor = #colorLiteral(red: 0.5372059941, green: 0.5372863412, blue: 0.5371884108, alpha: 1)
96 | randomB.slimTrack = 10
97 | randomB.thumbRadiusPadding = 0
98 | return randomB
99 |
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Icon-App-20x20@2x.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "Icon-App-20x20@3x.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "Icon-App-29x29@1x.png",
17 | "idiom" : "iphone",
18 | "scale" : "1x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "Icon-App-29x29@2x.png",
23 | "idiom" : "iphone",
24 | "scale" : "2x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "Icon-App-29x29@3x.png",
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "29x29"
32 | },
33 | {
34 | "filename" : "Icon-App-40x40@2x.png",
35 | "idiom" : "iphone",
36 | "scale" : "2x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "Icon-App-40x40@3x.png",
41 | "idiom" : "iphone",
42 | "scale" : "3x",
43 | "size" : "40x40"
44 | },
45 | {
46 | "filename" : "Icon-App-60x60@2x.png",
47 | "idiom" : "iphone",
48 | "scale" : "2x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "Icon-App-60x60@3x.png",
53 | "idiom" : "iphone",
54 | "scale" : "3x",
55 | "size" : "60x60"
56 | },
57 | {
58 | "filename" : "Icon-App-20x20@1x.png",
59 | "idiom" : "ipad",
60 | "scale" : "1x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "Icon-App-20x20@2x.png",
65 | "idiom" : "ipad",
66 | "scale" : "2x",
67 | "size" : "20x20"
68 | },
69 | {
70 | "filename" : "Icon-App-29x29@1x.png",
71 | "idiom" : "ipad",
72 | "scale" : "1x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "Icon-App-29x29@2x.png",
77 | "idiom" : "ipad",
78 | "scale" : "2x",
79 | "size" : "29x29"
80 | },
81 | {
82 | "filename" : "Icon-App-40x40@1x.png",
83 | "idiom" : "ipad",
84 | "scale" : "1x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "Icon-App-40x40@2x.png",
89 | "idiom" : "ipad",
90 | "scale" : "2x",
91 | "size" : "40x40"
92 | },
93 | {
94 | "filename" : "Icon-App-76x76@1x.png",
95 | "idiom" : "ipad",
96 | "scale" : "1x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "Icon-App-76x76@2x.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "76x76"
104 | },
105 | {
106 | "filename" : "Icon-App-83.5x83.5@2x.png",
107 | "idiom" : "ipad",
108 | "scale" : "2x",
109 | "size" : "83.5x83.5"
110 | },
111 | {
112 | "filename" : "ItunesArtwork@2x.png",
113 | "idiom" : "ios-marketing",
114 | "scale" : "1x",
115 | "size" : "1024x1024"
116 | }
117 | ],
118 | "info" : {
119 | "author" : "xcode",
120 | "version" : 1
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check@3x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check.imageset/check@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/check.imageset/check@3x.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check1.imageset/check1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/check1.imageset/check1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check9.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/check9.imageset/check9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/check9.imageset/check9.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "close.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/close.imageset/close.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/close.imageset/close.pdf
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cross1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross1.imageset/cross1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/cross1.imageset/cross1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cross24.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross24.imageset/cross24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/cross24.imageset/cross24.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cross7.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/cross7.imageset/cross7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/cross7.imageset/cross7.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/go1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "go1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/go1.imageset/go1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/go1.imageset/go1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/go2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "go2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/go2.imageset/go2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/go2.imageset/go2.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/icon_check_primary_dark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_check_primary_dark.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/icon_check_primary_dark.imageset/icon_check_primary_dark.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/icon_check_primary_dark.imageset/icon_check_primary_dark.pdf
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/icon_close_dark_purple.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon_close_dark_purple.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/icon_close_dark_purple.imageset/icon_close_dark_purple.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/icon_close_dark_purple.imageset/icon_close_dark_purple.pdf
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/left.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "left.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/left.imageset/left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/left.imageset/left.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/off1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "off1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/off1.imageset/off1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/off1.imageset/off1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/off2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "off2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/off2.imageset/off2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/off2.imageset/off2.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/onTick.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "onTick.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/onTick.imageset/onTick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/onTick.imageset/onTick.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/q1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "q1.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/q1.imageset/q1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/q1.imageset/q1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/right.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "right.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/right.imageset/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/right.imageset/right.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/switch-animation-post.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "switch-animation-post.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/switch-animation-post.imageset/switch-animation-post.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/switch-animation-post.imageset/switch-animation-post.jpg
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "thumb.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb.imageset/thumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/thumb.imageset/thumb.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "thumb1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb1.imageset/thumb1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/thumb1.imageset/thumb1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "thumb12.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb12.imageset/thumb12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/thumb12.imageset/thumb12.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "thumb4.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb4.imageset/thumb4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/thumb4.imageset/thumb4.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "thumb7.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/thumb7.imageset/thumb7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/thumb7.imageset/thumb7.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/w1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "w1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Assets.xcassets/w1.imageset/w1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/SwitchesDemo/Resources/Assets.xcassets/w1.imageset/w1.png
--------------------------------------------------------------------------------
/SwitchesDemo/Resources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | Switches
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/SwitchesDemo/Storyboard/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/SwitchesDemoTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwitchesDemoTests/SwitchesDemoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchesDemoTests.swift
3 | // SwitchesDemoTests
4 | //
5 | // Created by Jawad Ali on 30/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwitchesDemo
11 |
12 | class SwitchesDemoTests: XCTestCase {
13 |
14 | override func setUpWithError() throws {
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDownWithError() throws {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | }
21 |
22 | func testExample() throws {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() throws {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/SwitchesDemoUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwitchesDemoUITests/SwitchesDemoUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchesDemoUITests.swift
3 | // SwitchesDemoUITests
4 | //
5 | // Created by Jawad Ali on 30/08/2020.
6 | // Copyright © 2020 Jawad Ali. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class SwitchesDemoUITests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 |
16 | // In UI tests it is usually best to stop immediately when a failure occurs.
17 | continueAfterFailure = false
18 |
19 | // 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.
20 | }
21 |
22 | override func tearDownWithError() throws {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | }
25 |
26 | func testExample() throws {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use recording to get started writing UI tests.
32 | // Use XCTAssert and related functions to verify your tests produce the correct results.
33 | }
34 |
35 | func testLaunchPerformance() throws {
36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
37 | // This measures how long it takes to launch your application.
38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
39 | XCUIApplication().launch()
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/images/Screen Recording 2020-08-31 at 3.39.54 PM.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/images/Screen Recording 2020-08-31 at 3.39.54 PM.gif
--------------------------------------------------------------------------------
/images/abcd:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/ezgif.com-video-to-gif-23.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/images/ezgif.com-video-to-gif-23.gif
--------------------------------------------------------------------------------
/images/ezgif.com-video-to-gif-24.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/images/ezgif.com-video-to-gif-24.gif
--------------------------------------------------------------------------------
/images/ezgif.com-video-to-gif-25.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/images/ezgif.com-video-to-gif-25.gif
--------------------------------------------------------------------------------
/images/ezgif.com-video-to-gif-26.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jwd-ali/Switch-Animations/71626e8b569d7bfd28ad6d748121d315e4d98bf7/images/ezgif.com-video-to-gif-26.gif
--------------------------------------------------------------------------------