├── .gitignore
├── Example
├── Showcase
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-76.png
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-76@2x.png
│ │ │ ├── Icon-Small.png
│ │ │ ├── Icon-83.5@2x.png
│ │ │ ├── Icon-Small-40.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ ├── Icon-Small@3x.png
│ │ │ ├── Icon-Small-40@2x.png
│ │ │ ├── Icon-Small-40@3x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Style.swift
│ ├── ShowcaseViewController.swift
│ ├── TabBarController.swift
│ ├── AnimatedIcon+Style.swift
│ ├── TabBar.swift
│ ├── SettingsViewController.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
└── Showcase.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── .codeclimate.yml
├── Icons.playground
├── Pages
│ ├── Showcase.xcplaygroundpage
│ │ ├── Resources
│ │ │ └── AnimatedStar.gif
│ │ └── Contents.swift
│ ├── Export.xcplaygroundpage
│ │ └── Contents.swift
│ └── Basics.xcplaygroundpage
│ │ └── Contents.swift
├── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── contents.xcplayground
└── Sources
│ ├── Extensions
│ ├── CGFloat+InitWithBool.swift
│ ├── Bool+InitWithCGFloat.swift
│ ├── UIBezierPath+IconInit.swift
│ ├── CGFloat+CutAndMap.swift
│ ├── UIColor+IconColors.swift
│ ├── UIColor+Between.swift
│ ├── UIColor+RGB.swift
│ └── UIColor+HSB.swift
│ ├── Main classes
│ ├── AnimationFunctions.swift
│ ├── AnimationLayer.swift
│ ├── AnimatedIcon+Appearance.swift
│ ├── AnimatedIcon+Inspectable.swift
│ ├── AnimatedIconExporter.swift
│ └── AnimatedIcon.swift
│ └── Icons
│ ├── PlayStopIcon.swift
│ ├── CheckmarkIcon.swift
│ ├── SoundwaveIcon.swift
│ ├── TextAlignIcon.swift
│ ├── EllipsisIcon.swift
│ ├── PlusMinusIcon.swift
│ ├── HeartIcon.swift
│ ├── PaperclipIcon.swift
│ ├── BurgerIcon.swift
│ ├── SmileIcon.swift
│ ├── EarthIcon.swift
│ ├── StarIcon.swift
│ ├── PlayPauseIcon.swift
│ ├── SettingsIcon.swift
│ ├── DropPinIcon.swift
│ ├── BikeIcon.swift
│ └── FingerprintIcon.swift
├── .swiftpm
└── xcode
│ ├── package.xcworkspace
│ └── contents.xcworkspacedata
│ └── xcshareddata
│ └── xcschemes
│ └── MKJIcons.xcscheme
├── .jazzy.yaml
├── Package.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | xcuserdata
2 | *.xctimeline
3 | build
4 | docs
5 |
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | tailor:
3 | enabled: true
4 |
5 | ratings:
6 | paths:
7 | - "**.swift"
8 | exclude_paths:
9 | - "Icons.playground/Pages/**/*"
10 |
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
--------------------------------------------------------------------------------
/Icons.playground/Pages/Showcase.xcplaygroundpage/Resources/AnimatedStar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mkj-is/MKJIcons/HEAD/Icons.playground/Pages/Showcase.xcplaygroundpage/Resources/AnimatedStar.gif
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Icons.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | sdk: iphone
2 | author: Matěj Kašpar Jirásek
3 | author_url: http://mkj.is
4 | module: MKJIcons
5 | version: 1.0
6 | copyright: Copyright 2016 Matěj Kašpar Jirásek
7 | readme: README.md
8 | github_url: https://github.com/mkj-is/MKJIcons
9 |
--------------------------------------------------------------------------------
/Example/Showcase.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Icons.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Icons.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Showcase.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/CGFloat+InitWithBool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloat+ToBool.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 26/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CGFloat {
12 | init(_ bool: Bool) {
13 | self = bool ? 1 : 0
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/Bool+InitWithCGFloat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bool+ToCGFloat.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 26/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension Bool {
12 | init(_ float: CGFloat) {
13 | self = !float.isZero
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "MKJIcons",
7 | platforms: [
8 | .iOS(.v8),
9 | .tvOS(.v9)
10 | ],
11 | products: [
12 | .library(
13 | name: "MKJIcons",
14 | targets: ["MKJIcons"])
15 | ],
16 | targets: [
17 | .target(
18 | name: "MKJIcons",
19 | path: "Icons.playground/Sources")
20 | ]
21 | )
22 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/UIBezierPath+IconInit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIBezierPath+IconInit.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 27/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIBezierPath {
12 | convenience init(style: AnimatedIcon) {
13 | self.init()
14 | lineWidth = style.scaledLineWidth
15 | lineCapStyle = style.lineCap
16 | lineJoinStyle = style.lineJoin
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example/Showcase/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 18/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MKJIcons
11 |
12 | @UIApplicationMain
13 | final class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
18 | return true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Example/Showcase/Style.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Style.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 19/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct Style {
12 | var lineCap = 2
13 | var lineJoin = 2
14 | var lineWidth: CGFloat = 2
15 | var animationDuration: Double = 0.4
16 | var animationColorMode = 0
17 | var animationTimingFunction = 4
18 | var animationRepeat = false
19 | }
20 |
21 | protocol StyleUpdateDelegate: AnyObject {
22 | func styleUpdated(_ style: Style)
23 | }
24 |
--------------------------------------------------------------------------------
/Example/Showcase/ShowcaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 18/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MKJIcons
11 |
12 | final class ShowcaseViewController: UIViewController, StyleUpdateDelegate {
13 | func styleUpdated(_ style: Style) {
14 | for subview in view.subviews {
15 | if let icon = subview as? AnimatedIcon {
16 | icon.applyStyle(style: style)
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Example/Showcase/TabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBarController.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Kašpar Jirásek on 29/11/2019.
6 | // Copyright © 2019 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class TabBarController: UITabBarController, StyleUpdateDelegate {
12 | func styleUpdated(_ style: Style) {
13 | viewControllers?
14 | .compactMap { $0 as? StyleUpdateDelegate }
15 | .forEach { $0?.styleUpdated(style) }
16 | (tabBar as? StyleUpdateDelegate)?.styleUpdated(style)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example/Showcase/AnimatedIcon+Style.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimatedIcon+Style.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 22/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MKJIcons
11 |
12 | extension AnimatedIcon {
13 | func applyStyle(style: Style) {
14 | lineWidth = style.lineWidth
15 | lineCapStyle = style.lineCap
16 | lineJoinStyle = style.lineJoin
17 | animationColorMode = style.animationColorMode
18 | animationTimingFunction = style.animationTimingFunction
19 | animationDuration = style.animationDuration
20 | animationRepeat = style.animationRepeat
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/CGFloat+CutAndMap.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloat+LimitAndMap.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 28/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CGFloat {
12 |
13 | func constrain(low: CGFloat, high: CGFloat) -> CGFloat {
14 | if self < low {
15 | return low
16 | }
17 | if self > high {
18 | return high
19 | }
20 | return self
21 | }
22 |
23 | func map(min: CGFloat, max: CGFloat, from: CGFloat, to: CGFloat) -> CGFloat {
24 | return from + (to - from) * ((self - min) / (max - min))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimationFunctions.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | struct AnimationFunctions {
4 |
5 | // MARK: - Simple functions
6 |
7 | static func linear(x: CGFloat) -> CGFloat {
8 | return x
9 | }
10 |
11 | // MARK: - Sinusoidal functions
12 |
13 | static func sinEaseIn(x: CGFloat) -> CGFloat {
14 | if x <= 0 {
15 | return 0
16 | } else if x >= 1 {
17 | return 1
18 | } else {
19 | return 1 - sin((x+1) * .pi / 2)
20 | }
21 | }
22 |
23 | static func sinEaseOut(x: CGFloat) -> CGFloat {
24 | if x <= 0 {
25 | return 0
26 | } else if x >= 1 {
27 | return 1
28 | } else {
29 | return sin(x * .pi / 2)
30 | }
31 | }
32 |
33 | static func sinEaseInOut(x: CGFloat) -> CGFloat {
34 | if x <= 0 {
35 | return 0
36 | } else if x >= 1 {
37 | return 1
38 | } else {
39 | return (1 + sin((-1.0/2.0 + x) * .pi)) / 2
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/UIColor+IconColors.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public extension UIColor {
4 |
5 | // MARK: - Basic icon colors
6 |
7 | static var iconRedColor: UIColor {
8 | return UIColor(red: 1.000, green: 0.270, blue: 0.270, alpha: 1.000)
9 | }
10 |
11 | static var iconOrangeColor: UIColor {
12 | return iconRedColor.colorWithHueComponent(hue: iconRedColor.hue + 0.1)
13 | }
14 |
15 | static var iconLightGreenColor: UIColor {
16 | return iconRedColor.colorWithHueComponent(hue: iconRedColor.hue + 0.2)
17 | }
18 |
19 | static var iconCyanColor: UIColor {
20 | return iconRedColor.colorWithHueComponent(hue: iconRedColor.hue + 0.4)
21 | }
22 |
23 | static var iconDefault: UIColor {
24 | if #available(iOS 13.0, tvOS 10.0, *) {
25 | return UIColor { traits in
26 | if traits.userInterfaceStyle == .dark {
27 | return .white
28 | }
29 | return .black
30 | }
31 | }
32 | return .black
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/UIColor+Between.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public enum UIColorMode {
4 | case rgb, hsb
5 | }
6 |
7 | typealias UIColorComponents = (CGFloat, CGFloat, CGFloat, CGFloat)
8 |
9 | public extension UIColor {
10 |
11 | // MARK: - Color between two other colors
12 |
13 | convenience init(between color1: UIColor, and color2: UIColor, using: UIColorMode, ratio: CGFloat) {
14 | let components1: UIColorComponents = using == .rgb ? color1.rgbComponents : color1.hsbComponents
15 | let components2: UIColorComponents = using == .rgb ? color2.rgbComponents : color2.hsbComponents
16 |
17 | let c0 = components1.0 + (components2.0 - components1.0) * ratio
18 | let c1 = components1.1 + (components2.1 - components1.1) * ratio
19 | let c2 = components1.2 + (components2.2 - components1.2) * ratio
20 | let c3 = components1.3 + (components2.3 - components1.3) * ratio
21 |
22 | if using == .rgb {
23 | self.init(red: c0, green: c1, blue: c2, alpha: c3)
24 | } else {
25 | self.init(hue: c0, saturation: c1, brightness: c2, alpha: c3)
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Example/Showcase/TabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBar.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 19/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MKJIcons
11 |
12 | final class TabBar: UITabBar, StyleUpdateDelegate {
13 | required init?(coder aDecoder: NSCoder) {
14 | super.init(coder: aDecoder)
15 | tintColor = .iconOrangeColor
16 | styleUpdated()
17 | }
18 |
19 | func styleUpdated(_ style: Style = Style()) {
20 | let iconFrame = CGRect(x: 0, y: 0, width: 60, height: 60)
21 |
22 | let starIcon = StarIcon(frame: iconFrame)
23 | let settingsIcon = SettingsIcon(frame: iconFrame)
24 |
25 | starIcon.applyStyle(style: style)
26 | settingsIcon.applyStyle(style: style)
27 |
28 | if let items = self.items {
29 | let starImage = starIcon.image(at: 1)
30 | let settingsImage = settingsIcon.image()
31 |
32 | items[0].image = starImage
33 | items[1].image = settingsImage
34 |
35 | items[0].selectedImage = starImage
36 | items[1].selectedImage = settingsImage
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimationLayer.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class AnimationLayer: CALayer {
4 |
5 | // MARK: - Properties
6 |
7 | @NSManaged var value: CGFloat
8 |
9 | // MARK: - Initialization
10 |
11 | override init() {
12 | super.init()
13 | value = 0.0
14 | }
15 |
16 | override init(layer: Any) {
17 | super.init(layer: layer)
18 |
19 | if let layer = layer as? AnimationLayer {
20 | value = layer.value
21 | }
22 |
23 | }
24 |
25 | required init?(coder aDecoder: NSCoder) {
26 | super.init(coder: aDecoder)
27 | value = 0.0
28 | }
29 |
30 | // MARK: - Animation of the value
31 |
32 | override class func needsDisplay(forKey: String) -> Bool {
33 | if forKey == "value" {
34 | return true
35 | }
36 | return super.needsDisplay(forKey: forKey)
37 | }
38 |
39 | override func action(forKey event: String) -> CAAction? {
40 | if event == "value" {
41 | let animation = CABasicAnimation(keyPath: event)
42 | animation.fromValue = presentation()?.value(forKey: event)
43 | return animation
44 | }
45 | return super.action(forKey: event)
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/UIColor+RGB.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public typealias UIColorRGBComponents = (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
4 |
5 | public extension UIColor {
6 |
7 | // MARK: - Getting RGB components
8 |
9 | var red: CGFloat {
10 | return rgbComponents.red
11 | }
12 |
13 | var green: CGFloat {
14 | return rgbComponents.green
15 | }
16 |
17 | var blue: CGFloat {
18 | return rgbComponents.blue
19 | }
20 |
21 | var alpha: CGFloat {
22 | return rgbComponents.alpha
23 | }
24 |
25 | var rgbComponents: UIColorRGBComponents {
26 | var components: UIColorRGBComponents = (0.0, 0.0, 0.0, 0.0)
27 | getRed(&components.red, green: &components.green, blue: &components.blue, alpha: &components.alpha)
28 | return components
29 | }
30 |
31 | // MARK: - Creating from RGB components
32 |
33 | func colorWithRedComponent(red: CGFloat) -> UIColor {
34 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
35 | }
36 |
37 | func colorWithGreenComponent(green: CGFloat) -> UIColor {
38 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
39 | }
40 |
41 | func colorWithBlueComponent(blue: CGFloat) -> UIColor {
42 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Extensions/UIColor+HSB.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public typealias UIColorHSBComponents = (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)
4 |
5 | public extension UIColor {
6 |
7 | // MARK: - Getting HSB components
8 |
9 | var hue: CGFloat {
10 | return hsbComponents.hue
11 | }
12 |
13 | var saturation: CGFloat {
14 | return hsbComponents.saturation
15 | }
16 |
17 | var brightness: CGFloat {
18 | return hsbComponents.brightness
19 | }
20 |
21 | var hsbComponents: UIColorHSBComponents {
22 | var components: UIColorHSBComponents = (0.0, 0.0, 0.0, 0.0)
23 | getHue(&components.hue, saturation: &components.saturation, brightness: &components.brightness, alpha: &components.alpha)
24 | return components
25 | }
26 |
27 | // MARK: - Creating from HSB components
28 |
29 | func colorWithHueComponent(hue: CGFloat) -> UIColor {
30 | return UIColor(hue: hue.truncatingRemainder(dividingBy: 1), saturation: saturation, brightness: brightness, alpha: alpha)
31 | }
32 |
33 | func colorWithBrightnessComponent(brightness: CGFloat) -> UIColor {
34 | return UIColor(hue: hue.truncatingRemainder(dividingBy: 1), saturation: saturation, brightness: brightness, alpha: alpha)
35 | }
36 |
37 | func colorWithSaturationComponent(saturation: CGFloat) -> UIColor {
38 | return UIColor(hue: hue.truncatingRemainder(dividingBy: 1), saturation: saturation, brightness: brightness, alpha: alpha)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Icons.playground/Pages/Export.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | //:
2 | //: # Animated icons
3 | //:
4 | //: *Designed and developed by Matěj K. Jirásek ([mkj.is](http://mkj.is))*
5 | //:
6 | //: Full documentation is available here:
7 | //:
8 | //: [**Go to previous chapter.**](@previous)
9 | //:
10 | //: -----
11 | //:
12 | //: This chapter shows us how to export bitmap image sequences.
13 | //:
14 | //: In the framework there is a special class for exporting images
15 | //: and their sequences from icons. You assign the icon to the exporter
16 | //: and then save the result and that is all!
17 | //:
18 | //: **If you are view this documentation in the playground and want to export the icons, then you need to have
19 | //: *Shared Playground Data* folder in your user *Documents* folder.**
20 | //:
21 |
22 | import UIKit
23 | import PlaygroundSupport
24 |
25 | // We create the icon which will be 100x100 pixels
26 | let icon = CheckmarkIcon(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
27 |
28 | // Then we tell where we would like the sequence to be stored
29 | let folder = playgroundSharedDataDirectory.appendingPathComponent("checkmark_forward")
30 |
31 | // We can tell the exporter how many frames the animation has
32 | let frameCount = 50
33 |
34 | // Also, there is an option to export animation going once forward,
35 | // once backward or forward and back in one export
36 | let direction = AnimatedIconExporterDirection.forwardAndBack
37 |
38 | // Then we create the exporter and save the result!
39 | let exporter = AnimatedIconExporter(icon: icon, folder: folder, direction: direction, count: frameCount)
40 |
41 | exporter.save()
42 |
--------------------------------------------------------------------------------
/Example/Showcase/SettingsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.swift
3 | // Showcase
4 | //
5 | // Created by Matěj Jirásek on 18/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class SettingsViewController: UIViewController {
12 |
13 | weak var delegate: StyleUpdateDelegate?
14 |
15 | private var style = Style() {
16 | didSet {
17 | delegate?.styleUpdated(style)
18 | }
19 | }
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 | delegate = tabBarController as? StyleUpdateDelegate
24 | }
25 |
26 | // MARK: - Interface actions
27 |
28 | @IBAction private func lineWidthChanged(_ sender: UISlider) {
29 | style.lineWidth = CGFloat(sender.value)
30 | }
31 |
32 | @IBAction private func lineCapChanged(_ sender: UISegmentedControl) {
33 | style.lineCap = sender.selectedSegmentIndex
34 | }
35 |
36 | @IBAction private func lineJoinChanged(_ sender: UISegmentedControl) {
37 | style.lineJoin = sender.selectedSegmentIndex
38 | }
39 |
40 | @IBAction private func animationDurationChanged(_ sender: UISlider) {
41 | style.animationDuration = Double(sender.value)
42 | }
43 |
44 | @IBAction private func colorModeChanged(_ sender: UISegmentedControl) {
45 | style.animationColorMode = sender.selectedSegmentIndex
46 | }
47 |
48 | @IBAction private func animationTimingFunctionChanged(_ sender: UISegmentedControl) {
49 | style.animationTimingFunction = sender.selectedSegmentIndex + 1
50 | }
51 |
52 | @IBAction private func animationRepeatChanged(_ sender: UISwitch) {
53 | style.animationRepeat = sender.isOn
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Example/Showcase/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarTintParameters
34 |
35 | UINavigationBar
36 |
37 | Style
38 | UIBarStyleDefault
39 | Translucent
40 |
41 |
42 |
43 | UISupportedInterfaceOrientations
44 |
45 | UIInterfaceOrientationPortrait
46 |
47 | UISupportedInterfaceOrientations~ipad
48 |
49 | UIInterfaceOrientationPortrait
50 | UIInterfaceOrientationPortraitUpsideDown
51 | UIInterfaceOrientationLandscapeLeft
52 | UIInterfaceOrientationLandscapeRight
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Icons.playground/Pages/Basics.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | //:
2 | //: # Animated icons
3 | //:
4 | //: *Designed and developed by Matěj K. Jirásek ([mkj.is](http://mkj.is))*
5 | //:
6 | //: Full documentation is available here:
7 | //:
8 | //: - [**Go to previous chapter.**](@previous)
9 | //: - [**Go to next chapter.**](@next)
10 | //:
11 | //: -----
12 | //:
13 | //: This chapter shows how to configure the icon style and appearance.
14 | //:
15 | //: Properties listed below can be changed for all the icons, but many of them have much more settings. Also,
16 | //: these basic values can be set using `UIAppearance` on the application start. If you choose to use this way,
17 | //: then all the icons created after will inherit these properties.
18 | //:
19 | //: And the best thing is, that the icons are `IBDesignable`. That means if you add the to your `.xib` or `.storyboard`,
20 | //: you can see how they will look in your application and you can prototype the user interface really fast.
21 | //:
22 |
23 | // We need to import basic frameworks so this example can work
24 | import UIKit
25 | import PlaygroundSupport
26 |
27 | // Then we create the icon
28 | let icon = BikeIcon(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
29 |
30 | // We can set the line parameters
31 | icon.lineCap = .round
32 | icon.lineJoin = .round
33 | icon.lineWidth = 6
34 |
35 | // We make the icon to animate longer so we can see the animation in more detail
36 | icon.animationDuration = 2
37 |
38 | // If you animate using HSB the animation will be really colorful
39 | // (Or you can of course stock with RGB, if you are conservative)
40 | icon.colorMode = .hsb
41 |
42 | // We make the icon visible by default, the icon will animate at the beginning!
43 | icon.visible = true
44 |
45 | // Then we assign the icon to assistant editor
46 | PlaygroundPage.current.liveView = icon
47 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimatedIcon+Appearance.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimatedIcon+Appearance.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 19/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public extension AnimatedIcon {
12 |
13 | // MARK: - Appearance protocol support
14 |
15 | func appearanceLineWidth() -> CGFloat {
16 | return lineWidth
17 | }
18 |
19 | func setAppearanceLineWidth(property: CGFloat) {
20 | lineWidth = property
21 | }
22 |
23 | func appearanceFillAlpha() -> CGFloat {
24 | return fillAlpha
25 | }
26 |
27 | func setAppearanceFillAlpha(property: CGFloat) {
28 | fillAlpha = property
29 | }
30 |
31 | func appearanceLineCapStyle() -> Int {
32 | return lineCapStyle
33 | }
34 |
35 | func setAppearanceLineCapStyle(property: Int) {
36 | lineCapStyle = property
37 | }
38 |
39 | func appearanceLineJoinStyle() -> Int {
40 | return lineJoinStyle
41 | }
42 |
43 | func setAppearanceLineJoinStyle(property: Int) {
44 | lineJoinStyle = property
45 | }
46 |
47 | func appearanceAnimationDuration() -> CGFloat {
48 | return CGFloat(animationDuration)
49 | }
50 |
51 | func setAppearanceAnimationDuration(property: CGFloat) {
52 | animationDuration = Double(property)
53 | }
54 |
55 | func appearanceAnimationTimingFunction() -> Int {
56 | return animationTimingFunction
57 | }
58 |
59 | func setAppearanceAnimationTimingFunction(property: Int) {
60 | animationTimingFunction = property
61 | }
62 |
63 | func appearanceAnimationColorMode() -> Int {
64 | return animationColorMode
65 | }
66 |
67 | func setAppearanceAnimationColorMode(property: Int) {
68 | animationColorMode = property
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Example/Showcase/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 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/PlayStopIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class PlayStopIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var size: CGFloat = 40 {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var playColor: UIColor = .iconLightGreenColor {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var stopColor: UIColor = .iconRedColor {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var playing: Bool {
35 | get {
36 | return Bool(value)
37 | }
38 | set {
39 | value = CGFloat(newValue)
40 | }
41 | }
42 |
43 | // MARK: - Drawing methods
44 |
45 | override func draw(time: CGFloat = 0) {
46 | guard let context = UIGraphicsGetCurrentContext() else {
47 | return
48 | }
49 |
50 | let strokeColor = UIColor(between: playColor, and: stopColor, using: colorMode, ratio: time)
51 | strokeColor.setStroke()
52 |
53 | let fillColor = strokeColor.withAlphaComponent(fillAlpha)
54 | fillColor.setFill()
55 |
56 | // Variable Declarations
57 | let halfSize = size / 2.0
58 |
59 | context.scaleBy(x: scale, y: scale)
60 |
61 | // Left line Drawing
62 | context.saveGState()
63 | context.translateBy(x: 50, y: 50)
64 |
65 | let leftLinePath = UIBezierPath(style: self)
66 | leftLinePath.move(to: CGPoint(x: -halfSize, y: halfSize))
67 | leftLinePath.addLine(to: CGPoint(x: halfSize, y: halfSize * time))
68 | leftLinePath.addLine(to: CGPoint(x: halfSize, y: -halfSize * time))
69 | leftLinePath.addLine(to: CGPoint(x: -halfSize, y: -halfSize))
70 | leftLinePath.addLine(to: CGPoint(x: -halfSize, y: halfSize))
71 | leftLinePath.close()
72 |
73 | leftLinePath.stroke()
74 | leftLinePath.fill()
75 |
76 | context.restoreGState()
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/CheckmarkIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class CheckmarkIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var checkmarkColor: UIColor = .iconLightGreenColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 | @IBInspectable public var crossColor: UIColor = .iconRedColor {
22 | didSet {
23 | layer.setNeedsDisplay()
24 | }
25 | }
26 |
27 | @IBInspectable public var checked: Bool {
28 | get {
29 | return Bool(value)
30 | }
31 | set {
32 | value = CGFloat(newValue)
33 | }
34 | }
35 |
36 | // MARK: - Drawing methods
37 |
38 | override func draw(time: CGFloat = 0) {
39 | guard let context = UIGraphicsGetCurrentContext() else {
40 | return
41 | }
42 |
43 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
44 |
45 | let currentColor = UIColor(between: crossColor, and: checkmarkColor, using: colorMode, ratio: time)
46 |
47 | // Variable Declarations
48 | let phase: CGFloat = -time * 111
49 | let dash: CGFloat = (1 - time / 2.0) * 57
50 |
51 | context.scaleBy(x: scale, y: scale)
52 |
53 | // Static line Drawing
54 | let staticLinePath = UIBezierPath(style: self)
55 | staticLinePath.move(to: CGPoint(x: 70, y: 30))
56 | staticLinePath.addLine(to: CGPoint(x: 30, y: 70))
57 |
58 | currentColor.setStroke()
59 | staticLinePath.stroke()
60 |
61 | // Animated line Drawing
62 | let animatedLinePath = UIBezierPath(style: self)
63 | animatedLinePath.move(to: CGPoint(x: 30, y: 30))
64 | animatedLinePath.addCurve(to: CGPoint(x: 70, y: 70), controlPoint1: CGPoint(x: 30, y: 30), controlPoint2: CGPoint(x: 56.58, y: 56.58))
65 | animatedLinePath.addCurve(to: CGPoint(x: 30, y: 70), controlPoint1: CGPoint(x: 83.42, y: 83.42), controlPoint2: CGPoint(x: 46.03, y: 86.03))
66 | animatedLinePath.addCurve(to: CGPoint(x: 10, y: 50), controlPoint1: CGPoint(x: 13.97, y: 53.97), controlPoint2: CGPoint(x: 10, y: 50))
67 |
68 | context.saveGState()
69 | context.setLineDash(phase: phase, lengths: [dash, 200])
70 | animatedLinePath.stroke()
71 | context.restoreGState()
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/MKJIcons.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 |
--------------------------------------------------------------------------------
/Example/Showcase/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "size" : "29x29",
15 | "idiom" : "iphone",
16 | "filename" : "Icon-Small@2x.png",
17 | "scale" : "2x"
18 | },
19 | {
20 | "size" : "29x29",
21 | "idiom" : "iphone",
22 | "filename" : "Icon-Small@3x.png",
23 | "scale" : "3x"
24 | },
25 | {
26 | "size" : "40x40",
27 | "idiom" : "iphone",
28 | "filename" : "Icon-Small-40@2x.png",
29 | "scale" : "2x"
30 | },
31 | {
32 | "size" : "40x40",
33 | "idiom" : "iphone",
34 | "filename" : "Icon-Small-40@3x.png",
35 | "scale" : "3x"
36 | },
37 | {
38 | "size" : "60x60",
39 | "idiom" : "iphone",
40 | "filename" : "Icon-60@2x.png",
41 | "scale" : "2x"
42 | },
43 | {
44 | "size" : "60x60",
45 | "idiom" : "iphone",
46 | "filename" : "Icon-60@3x.png",
47 | "scale" : "3x"
48 | },
49 | {
50 | "idiom" : "ipad",
51 | "size" : "20x20",
52 | "scale" : "1x"
53 | },
54 | {
55 | "idiom" : "ipad",
56 | "size" : "20x20",
57 | "scale" : "2x"
58 | },
59 | {
60 | "size" : "29x29",
61 | "idiom" : "ipad",
62 | "filename" : "Icon-Small.png",
63 | "scale" : "1x"
64 | },
65 | {
66 | "size" : "29x29",
67 | "idiom" : "ipad",
68 | "filename" : "Icon-Small@2x.png",
69 | "scale" : "2x"
70 | },
71 | {
72 | "size" : "40x40",
73 | "idiom" : "ipad",
74 | "filename" : "Icon-Small-40.png",
75 | "scale" : "1x"
76 | },
77 | {
78 | "size" : "40x40",
79 | "idiom" : "ipad",
80 | "filename" : "Icon-Small-40@2x.png",
81 | "scale" : "2x"
82 | },
83 | {
84 | "size" : "76x76",
85 | "idiom" : "ipad",
86 | "filename" : "Icon-76.png",
87 | "scale" : "1x"
88 | },
89 | {
90 | "size" : "76x76",
91 | "idiom" : "ipad",
92 | "filename" : "Icon-76@2x.png",
93 | "scale" : "2x"
94 | },
95 | {
96 | "size" : "83.5x83.5",
97 | "idiom" : "ipad",
98 | "filename" : "Icon-83.5@2x.png",
99 | "scale" : "2x"
100 | },
101 | {
102 | "idiom" : "ios-marketing",
103 | "size" : "1024x1024",
104 | "scale" : "1x"
105 | }
106 | ],
107 | "info" : {
108 | "version" : 1,
109 | "author" : "xcode"
110 | }
111 | }
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimatedIcon+Inspectable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimatedIcon+Inspectable.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 19/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension AnimatedIcon {
12 |
13 | // MARK: - Additional inspectable properties
14 |
15 | @IBInspectable public var animationColorMode: Int {
16 | get {
17 | return colorMode == .hsb ? 0 : 1
18 | }
19 | set {
20 | colorMode = newValue < 1 ? .hsb : .rgb
21 | }
22 | }
23 |
24 | @IBInspectable public var animationTimingFunction: Int {
25 | get {
26 | switch timingFunctionName {
27 | case .linear:
28 | return 1
29 | case .easeIn:
30 | return 2
31 | case .easeOut:
32 | return 3
33 | case .easeInEaseOut:
34 | return 4
35 | default:
36 | return 0
37 | }
38 | }
39 | set {
40 | switch newValue {
41 | case 1:
42 | timingFunctionName = .linear
43 | case 2:
44 | timingFunctionName = .easeIn
45 | case 3:
46 | timingFunctionName = .easeOut
47 | case 4:
48 | timingFunctionName = .easeInEaseOut
49 | default:
50 | timingFunctionName = .default
51 | }
52 | }
53 | }
54 |
55 | @IBInspectable public var lineCapStyle: Int {
56 | get {
57 | switch lineCap {
58 | case .butt:
59 | return 0
60 | case .square:
61 | return 1
62 | default:
63 | return 2
64 | }
65 | }
66 | set(new) {
67 | switch new {
68 | case 0:
69 | lineCap = .butt
70 | case 1:
71 | lineCap = .square
72 | default:
73 | lineCap = .round
74 | }
75 | }
76 | }
77 |
78 | @IBInspectable public var lineJoinStyle: Int {
79 | get {
80 | switch lineJoin {
81 | case .bevel:
82 | return 0
83 | case .miter:
84 | return 1
85 | default:
86 | return 2
87 | }
88 | }
89 | set {
90 | switch newValue {
91 | case 0:
92 | lineJoin = .bevel
93 | case 1:
94 | lineJoin = .miter
95 | default:
96 | lineJoin = .round
97 | }
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/SoundwaveIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SoundwaveIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 27/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class SoundwaveIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconOrangeColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var lineCount: UInt = 9 {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var sinLineLength: CGFloat = 14 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var multiplier: CGFloat = 4 {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var size: CGFloat = 40 {
41 | didSet {
42 | layer.setNeedsDisplay()
43 | }
44 | }
45 |
46 | @IBInspectable public var progress: Bool {
47 | get {
48 | return Bool(value)
49 | }
50 | set {
51 | value = CGFloat(newValue)
52 | }
53 | }
54 |
55 | // MARK: - Helper properties
56 | var baseLineLength: CGFloat {
57 | get {
58 | return 20 - sinLineLength
59 | }
60 | }
61 |
62 | // MARK: - Drawing methods
63 |
64 | override func draw(time: CGFloat = 0) {
65 | guard let context = UIGraphicsGetCurrentContext() else {
66 | return
67 | }
68 |
69 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
70 | context.scaleBy(x: scale, y: scale)
71 |
72 | strokeColor.setStroke()
73 |
74 | // Draw lines
75 |
76 | let spaces: CGFloat = CGFloat(lineCount) - 1
77 | let pi = CGFloat.pi
78 | let baseLength = (size / 2 - sinLineLength) * 2.0
79 | let offset = (100 - size) / 2
80 |
81 | for i in 0...lineCount {
82 |
83 | let iterator = CGFloat(i)
84 | let x: CGFloat = offset + size / spaces * iterator
85 | let y: CGFloat = offset + (1 - sin((time + iterator / spaces) * multiplier * pi)) / 2.0 * sinLineLength
86 | let length: CGFloat = baseLength + (1 + sin((time + iterator / spaces) * multiplier * pi)) * sinLineLength
87 |
88 | // Bezier Drawing
89 | context.saveGState()
90 | context.translateBy(x: x, y: y)
91 |
92 | let bezierPath = UIBezierPath(style: self)
93 | bezierPath.move(to: CGPoint.zero)
94 | bezierPath.addLine(to: CGPoint(x: 0, y: length))
95 |
96 | bezierPath.stroke()
97 |
98 | context.restoreGState()
99 | }
100 |
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/TextAlignIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextAlignIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 28/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class TextAlignIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .white {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var width: CGFloat = 40 {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var shortWidth: CGFloat = 32 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var offset: CGFloat = 5 {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var lines: UInt = 7 {
41 | didSet {
42 | if lines < 2 {
43 | lines = 2
44 | }
45 | layer.setNeedsDisplay()
46 | }
47 | }
48 |
49 | @IBInspectable public var textAlignment: NSTextAlignment {
50 | get {
51 | switch value {
52 | case 1:
53 | return .right
54 | case 0.5:
55 | return .center
56 | default:
57 | return .left
58 | }
59 | }
60 | set {
61 | switch newValue {
62 | case .right:
63 | value = 1
64 | case .left:
65 | value = 0
66 | default:
67 | value = 0.5
68 | }
69 | }
70 | }
71 |
72 | // MARK: - Drawing methods
73 |
74 | override func draw(time: CGFloat = 0) {
75 | guard let context = UIGraphicsGetCurrentContext() else {
76 | return
77 | }
78 |
79 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
80 | context.scaleBy(x: scale, y: scale)
81 |
82 | strokeColor.setStroke()
83 |
84 | // Variable Declarations
85 | let x: CGFloat = 50 - width / 2.0
86 | let timeOffset: CGFloat = time * (width - shortWidth)
87 | let shortX: CGFloat = x + timeOffset
88 |
89 | for i in 0...lines - 1 {
90 |
91 | let short = i % 2 == 1
92 |
93 | context.saveGState()
94 | context.translateBy(x: short ? shortX : x, y: 34.5 + CGFloat(i) * 30 / CGFloat(lines - 1))
95 |
96 | let bezierPath = UIBezierPath(style: self)
97 | bezierPath.move(to: CGPoint(x: 0, y: 0))
98 | bezierPath.addLine(to: CGPoint(x: short ? shortWidth : width, y: 0))
99 | bezierPath.stroke()
100 |
101 | context.restoreGState()
102 | }
103 |
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/EllipsisIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EllipsisIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 08/05/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class EllipsisIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var fillColor: UIColor = .iconDefault {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var magnitude: CGFloat = 10 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var dotSize: CGFloat = 10 {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var progress: Bool {
41 | get {
42 | return Bool(value)
43 | }
44 | set {
45 | value = CGFloat(newValue)
46 | }
47 | }
48 |
49 | // MARK: - Drawing methods
50 |
51 | override func draw(time: CGFloat = 0) {
52 | guard let context = UIGraphicsGetCurrentContext() else {
53 | return
54 | }
55 |
56 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
57 | context.scaleBy(x: scale, y: scale)
58 |
59 | fillColor.withAlphaComponent(fillAlpha).setFill()
60 | strokeColor.setStroke()
61 |
62 | //// Variable Declarations
63 | let dotOffset: CGFloat = -dotSize / 2.0
64 | let yOffset: CGFloat = dotOffset + magnitude * sin(time * 360 * .pi / 180)
65 | let yCenterOffset: CGFloat = dotOffset + magnitude * sin(1.5 * time * 360 * .pi/180)
66 |
67 | //// Dot 1 Drawing
68 | context.saveGState()
69 | context.translateBy(x: 35, y: 50)
70 |
71 | let dot1Path = UIBezierPath(ovalIn: CGRect(x: dotOffset, y: yOffset, width: dotSize, height: dotSize))
72 | dot1Path.lineWidth = lineWidth
73 | dot1Path.fill()
74 | dot1Path.stroke()
75 |
76 | context.restoreGState()
77 |
78 | //// Dot 2 Drawing
79 | context.saveGState()
80 | context.translateBy(x: 50, y: 50)
81 |
82 | let dot2Path = UIBezierPath(ovalIn: CGRect(x: dotOffset, y: yCenterOffset, width: dotSize, height: dotSize))
83 | dot2Path.lineWidth = lineWidth
84 | dot2Path.fill()
85 | dot2Path.stroke()
86 |
87 | context.restoreGState()
88 |
89 | //// Dot 3 Drawing
90 | context.saveGState()
91 | context.translateBy(x: 65, y: 50)
92 |
93 | let dot3Path = UIBezierPath(ovalIn: CGRect(x: dotOffset, y: yOffset, width: dotSize, height: dotSize))
94 | dot3Path.lineWidth = lineWidth
95 | dot3Path.fill()
96 | dot3Path.stroke()
97 |
98 | context.restoreGState()
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/PlusMinusIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class PlusMinusIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var plusColor: UIColor = .iconLightGreenColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var minusColor: UIColor = .iconRedColor {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var circle: Bool = true {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var minus: Bool {
35 | get {
36 | return Bool(value)
37 | }
38 | set {
39 | value = CGFloat(newValue)
40 | }
41 | }
42 |
43 | // MARK: - Drawing methods
44 |
45 | override func draw(time: CGFloat = 0) {
46 | guard let context = UIGraphicsGetCurrentContext() else {
47 | return
48 | }
49 |
50 | let strokeColor = UIColor(between: plusColor, and: minusColor, using: colorMode, ratio: time)
51 | strokeColor.setStroke()
52 | let fillColor = strokeColor.withAlphaComponent(fillAlpha)
53 | fillColor.setFill()
54 |
55 | // Variable Declarations
56 | let verticalAngle: CGFloat = minus ? -90 - time * 90 : -180 - (1 - time) * 90
57 | let horizontalAngle: CGFloat = minus ? -time * 180 : -180 - (1 - time) * 180
58 | let lineLength: CGFloat = circle ? 20 : 40
59 | let pointPosition: CGFloat = lineLength / 2.0
60 | let negativePointPosition: CGFloat = -pointPosition
61 |
62 | context.scaleBy(x: scale, y: scale)
63 | context.translateBy(x: 50, y: 50)
64 |
65 | // Circle Drawing
66 | if circle {
67 |
68 | let circlePath = UIBezierPath(ovalIn: CGRect(x: -20, y: -20, width: 40, height: 40))
69 | circlePath.lineWidth = scaledLineWidth
70 | circlePath.fill()
71 | circlePath.stroke()
72 |
73 | }
74 |
75 | // Vertical line Drawing
76 | context.saveGState()
77 | context.rotate(by: -horizontalAngle * .pi / 180)
78 |
79 | let verticalLinePath = UIBezierPath(style: self)
80 | verticalLinePath.move(to: CGPoint(x: pointPosition, y: 0))
81 | verticalLinePath.addLine(to: CGPoint(x: negativePointPosition, y: 0))
82 |
83 | verticalLinePath.stroke()
84 |
85 | context.restoreGState()
86 |
87 | // Horizontal line Drawing
88 | context.saveGState()
89 | context.rotate(by: -verticalAngle * .pi / 180)
90 |
91 | let horizontalLinePath = UIBezierPath(style: self)
92 | horizontalLinePath.move(to: CGPoint(x: pointPosition, y: 0))
93 | horizontalLinePath.addLine(to: CGPoint(x: negativePointPosition, y: 0))
94 |
95 | horizontalLinePath.stroke()
96 |
97 | context.restoreGState()
98 |
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/HeartIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeartIcon.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 3/04/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class HeartIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconRedColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 | @IBInspectable public var fillColor: UIColor = .iconRedColor {
22 | didSet {
23 | layer.setNeedsDisplay()
24 | }
25 | }
26 | @IBInspectable public var twoLines: Bool = true {
27 | didSet {
28 | layer.setNeedsDisplay()
29 | }
30 | }
31 |
32 | @IBInspectable public var visible: Bool {
33 | get {
34 | return Bool(value)
35 | }
36 | set {
37 | value = CGFloat(newValue)
38 | }
39 | }
40 |
41 | // MARK: - Drawing methods
42 |
43 | override func draw(time: CGFloat = 0) {
44 | guard time > 0, let context = UIGraphicsGetCurrentContext() else {
45 | return
46 | }
47 |
48 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
49 |
50 | // Variable Declarations
51 | let dash: CGFloat = time * (twoLines ? 82 : 164)
52 | let gap: CGFloat = -5 + (1 - time) * (twoLines ? 82 : 164)
53 | let phase: CGFloat = -0.5
54 |
55 | context.scaleBy(x: scale, y: scale)
56 |
57 | // Bezier Drawing
58 | context.saveGState()
59 | context.translateBy(x: 50, y: 75)
60 | context.rotate(by: -45 * .pi / 180)
61 |
62 | let bezierPath = UIBezierPath(style: self)
63 | bezierPath.move(to: CGPoint(x: 30, y: -30.19))
64 | bezierPath.addLine(to: CGPoint(x: 30, y: -30))
65 | bezierPath.addCurve(to: CGPoint(x: 45, y: -15), controlPoint1: CGPoint(x: 38.28, y: -30), controlPoint2: CGPoint(x: 45, y: -23.28))
66 | bezierPath.addCurve(to: CGPoint(x: 30, y: 0), controlPoint1: CGPoint(x: 45, y: -6.72), controlPoint2: CGPoint(x: 38.28, y: 0))
67 | bezierPath.addLine(to: CGPoint(x: 0, y: 0))
68 | bezierPath.addLine(to: CGPoint(x: 0, y: -30))
69 | bezierPath.addCurve(to: CGPoint(x: 5.94, y: -41.95), controlPoint1: CGPoint(x: 0, y: -34.88), controlPoint2: CGPoint(x: 2.33, y: -39.21))
70 | bezierPath.addLine(to: CGPoint(x: 6.03, y: -42.02))
71 | bezierPath.addCurve(to: CGPoint(x: 15, y: -45), controlPoint1: CGPoint(x: 8.53, y: -43.89), controlPoint2: CGPoint(x: 11.64, y: -45))
72 | bezierPath.addCurve(to: CGPoint(x: 30, y: -30.19), controlPoint1: CGPoint(x: 23.22, y: -45), controlPoint2: CGPoint(x: 29.9, y: -38.39))
73 | bezierPath.close()
74 |
75 | strokeColor.setStroke()
76 | fillColor.withAlphaComponent(time * fillAlpha).setFill()
77 | context.saveGState()
78 |
79 | if time < 1 {
80 | context.setLineDash(phase: phase, lengths: [dash < 0 ? 0 : dash, gap < 0 ? 0 : gap])
81 | }
82 | bezierPath.fill()
83 | bezierPath.stroke()
84 | context.restoreGState()
85 |
86 | context.restoreGState()
87 |
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimatedIconExporter.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public enum AnimatedIconExporterDirection {
4 | case forward, backward, forwardAndBack
5 | }
6 |
7 | public class AnimatedIconExporter {
8 |
9 | var icon: AnimatedIcon
10 | var direction: AnimatedIconExporterDirection
11 | var count: Int
12 | var frames: [UIImage]
13 | var folder: URL
14 |
15 | // MARK: - Initialization
16 |
17 | public init(icon: AnimatedIcon, folder: URL, direction: AnimatedIconExporterDirection = .forward, count: Int = 50) {
18 | self.icon = icon
19 | self.direction = direction
20 | self.count = count
21 | self.folder = folder
22 | self.frames = []
23 | }
24 |
25 | // MARK: - Exporting & saving
26 |
27 | public func export() -> [UIImage] {
28 | frames = []
29 | for i in 0...count {
30 | frames.append(icon.image(at: position(i: i)))
31 | }
32 | return frames
33 | }
34 |
35 | public func save() -> Bool {
36 |
37 | var exported = true
38 |
39 | let name = NSStringFromClass(type(of: icon)).components(separatedBy: ".").last
40 |
41 | if !FileManager.default.fileExists(atPath: folder.path) {
42 | try! FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true, attributes: nil)
43 | }
44 |
45 | let formatter = DateFormatter()
46 | formatter.dateFormat = "YYYY-MM-dd_HH-mm-ss"
47 | let date = formatter.string(from: Date())
48 |
49 | let images = export()
50 | for i in 0...(images.count - 1) {
51 |
52 | let fileName = String(format: "%@_%@_%03d.png", arguments: [date, name!, i])
53 | let filePath = folder.appendingPathComponent(fileName)
54 |
55 | if let data = images[i].pngData() {
56 | do {
57 | try data.write(to: filePath)
58 | } catch {
59 | exported = false
60 | }
61 | } else {
62 | exported = false
63 | }
64 |
65 | }
66 | return exported
67 | }
68 |
69 | // MARK: - Helper functions
70 |
71 | func position(i: Int) -> CGFloat {
72 | var value = CGFloat(i) / CGFloat(count)
73 |
74 | // Calculate position of animation on timeline
75 | if direction == .backward {
76 | value = 1 - value
77 | } else if direction == .forwardAndBack {
78 | let truncatedByHalf = value.truncatingRemainder(dividingBy: 0.5)
79 | let truncatedByOne = value.truncatingRemainder(dividingBy: 1)
80 | value = truncatedByHalf * 2 * (truncatedByOne >= 0.5 ? -1 : 1) + (truncatedByOne >= 0.5 ? 1 : 0)
81 | }
82 |
83 | // Apply animation function
84 | switch icon.timingFunctionName {
85 | case .easeInEaseOut:
86 | value = AnimationFunctions.sinEaseInOut(x: value)
87 | case .easeIn:
88 | value = AnimationFunctions.sinEaseOut(x: value)
89 | case .easeOut:
90 | value = AnimationFunctions.sinEaseIn(x: value)
91 | default:
92 | value = AnimationFunctions.linear(x: value)
93 | }
94 |
95 | return value
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/PaperclipIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaperclipIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 27/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class PaperclipIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var visible: Bool {
23 | get {
24 | return Bool(value)
25 | }
26 | set {
27 | value = CGFloat(newValue)
28 | }
29 | }
30 |
31 | // MARK: - Drawing methods
32 |
33 | override func draw(time: CGFloat = 0) {
34 | guard time > 0, let context = UIGraphicsGetCurrentContext() else {
35 | return
36 | }
37 |
38 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
39 | context.scaleBy(x: scale, y: scale)
40 |
41 | strokeColor.setStroke()
42 |
43 | // Bezier Drawing
44 | let bezierPath = UIBezierPath(style: self)
45 | bezierPath.move(to: CGPoint(x: 41.28, y: 51.66))
46 | bezierPath.addCurve(to: CGPoint(x: 55, y: 37.44), controlPoint1: CGPoint(x: 43.98, y: 48.87), controlPoint2: CGPoint(x: 52.76, y: 39.57))
47 | bezierPath.addCurve(to: CGPoint(x: 60.49, y: 35.61), controlPoint1: CGPoint(x: 56.56, y: 35.96), controlPoint2: CGPoint(x: 58.52, y: 35.22))
48 | bezierPath.addCurve(to: CGPoint(x: 62.91, y: 45.52), controlPoint1: CGPoint(x: 65.06, y: 36.5), controlPoint2: CGPoint(x: 65.93, y: 42.4))
49 | bezierPath.addCurve(to: CGPoint(x: 60.59, y: 47.93), controlPoint1: CGPoint(x: 62.14, y: 46.33), controlPoint2: CGPoint(x: 61.36, y: 47.12))
50 | bezierPath.addCurve(to: CGPoint(x: 49.5, y: 59.4), controlPoint1: CGPoint(x: 56.89, y: 51.75), controlPoint2: CGPoint(x: 53.19, y: 55.58))
51 | bezierPath.addCurve(to: CGPoint(x: 40.98, y: 67.43), controlPoint1: CGPoint(x: 46.98, y: 62), controlPoint2: CGPoint(x: 44.25, y: 65.79))
52 | bezierPath.addCurve(to: CGPoint(x: 29.39, y: 64.15), controlPoint1: CGPoint(x: 36.92, y: 69.48), controlPoint2: CGPoint(x: 31.79, y: 68.2))
53 | bezierPath.addCurve(to: CGPoint(x: 30.96, y: 52.38), controlPoint1: CGPoint(x: 27.17, y: 60.39), controlPoint2: CGPoint(x: 28, y: 55.44))
54 | bezierPath.addCurve(to: CGPoint(x: 48.95, y: 33.76), controlPoint1: CGPoint(x: 36.95, y: 46.17), controlPoint2: CGPoint(x: 42.95, y: 39.97))
55 | bezierPath.addCurve(to: CGPoint(x: 52.73, y: 30.4), controlPoint1: CGPoint(x: 50.14, y: 32.54), controlPoint2: CGPoint(x: 51.28, y: 31.31))
56 | bezierPath.addCurve(to: CGPoint(x: 64.59, y: 29.62), controlPoint1: CGPoint(x: 56.28, y: 28.18), controlPoint2: CGPoint(x: 60.81, y: 27.82))
57 | bezierPath.addCurve(to: CGPoint(x: 67.67, y: 50.58), controlPoint1: CGPoint(x: 72.55, y: 33.41), controlPoint2: CGPoint(x: 73.63, y: 44.42))
58 | bezierPath.addCurve(to: CGPoint(x: 50.09, y: 68.77), controlPoint1: CGPoint(x: 61.81, y: 56.65), controlPoint2: CGPoint(x: 55.95, y: 62.71))
59 |
60 | context.setLineDash(phase: 0, lengths: [188 * time, 200])
61 | bezierPath.stroke()
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/BurgerIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BurgerIcon.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class BurgerIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var burgerColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 | @IBInspectable public var crossColor: UIColor = .iconRedColor {
22 | didSet {
23 | layer.setNeedsDisplay()
24 | }
25 | }
26 |
27 | @IBInspectable public var open: Bool {
28 | get {
29 | return Bool(value)
30 | }
31 | set {
32 | value = CGFloat(newValue)
33 | }
34 | }
35 |
36 | // MARK: - Drawing methods
37 |
38 | override func draw(time: CGFloat = 0) {
39 |
40 | let offset: CGFloat = 5
41 |
42 | guard let context = UIGraphicsGetCurrentContext() else {
43 | return
44 | }
45 |
46 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
47 |
48 | let currentColor = UIColor(between: burgerColor, and: crossColor, using: colorMode, ratio: time)
49 |
50 | // Variable Declarations
51 | let angle: CGFloat = time * 45
52 | let negativeAngle: CGFloat = -angle
53 | let localScale: CGFloat = 1 + time * 0.414
54 | let opacity = UIColor(red: burgerColor.red, green: burgerColor.green, blue: burgerColor.blue, alpha: burgerColor.alpha - time * burgerColor.alpha)
55 | let timedOffset: CGFloat = time * offset
56 | let negativeTimedOffset: CGFloat = -timedOffset
57 | let timeLineWidth: CGFloat = scaledLineWidth / localScale
58 |
59 | context.scaleBy(x: scale, y: scale)
60 |
61 | // Bottom Drawing
62 | context.saveGState()
63 | context.translateBy(x: 30, y: (timedOffset + 65))
64 | context.rotate(by: -angle * .pi / 180)
65 | context.scaleBy(x: localScale, y: localScale)
66 |
67 | let bottomPath = UIBezierPath(style: self)
68 | bottomPath.move(to: CGPoint(x: 40, y: 0))
69 | bottomPath.addLine(to: CGPoint(x: 0, y: 0))
70 |
71 | currentColor.setStroke()
72 | bottomPath.lineWidth = timeLineWidth
73 | bottomPath.stroke()
74 |
75 | context.restoreGState()
76 |
77 | // Middle Drawing
78 | context.saveGState()
79 | context.translateBy(x: 50, y: 50)
80 |
81 | let middlePath = UIBezierPath(style: self)
82 | middlePath.move(to: CGPoint(x: 20, y: 0))
83 | middlePath.addLine(to: CGPoint(x: -20, y: 0))
84 |
85 | opacity.setStroke()
86 | middlePath.stroke()
87 |
88 | context.restoreGState()
89 |
90 | // Top Drawing
91 | context.saveGState()
92 | context.translateBy(x: 30, y: (negativeTimedOffset + 35))
93 | context.rotate(by: -negativeAngle * .pi / 180)
94 | context.scaleBy(x: localScale, y: localScale)
95 |
96 | let topPath = UIBezierPath(style: self)
97 | topPath.move(to: CGPoint(x: 40, y: 0))
98 | topPath.addLine(to: CGPoint(x: 0, y: 0))
99 |
100 | currentColor.setStroke()
101 | topPath.lineWidth = timeLineWidth
102 | topPath.stroke()
103 |
104 | context.restoreGState()
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/SmileIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class SmileIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var sadColor: UIColor = .iconRedColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var happyColor: UIColor = .iconLightGreenColor {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var eyeMovement: CGFloat = 4 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var mouthMovement: CGFloat = 8 {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var showFace: Bool = true {
41 | didSet {
42 | layer.setNeedsDisplay()
43 | }
44 | }
45 |
46 | @IBInspectable public var sad: Bool {
47 | get {
48 | return Bool(value)
49 | }
50 | set {
51 | value = CGFloat(newValue)
52 | }
53 | }
54 |
55 | // MARK: - Drawing methods
56 |
57 | override func draw(time: CGFloat = 0) {
58 | guard let context = UIGraphicsGetCurrentContext() else {
59 | return
60 | }
61 |
62 | let strokeColor = UIColor(between: happyColor, and: sadColor, using: colorMode, ratio: time)
63 | strokeColor.setStroke()
64 | let fillColor = strokeColor.withAlphaComponent(fillAlpha)
65 | fillColor.setFill()
66 |
67 | // Variable Declarations
68 | let minusHalfLineWidth: CGFloat = -scaledLineWidth / 2.0
69 | let eyeOffset: CGFloat = -eyeMovement / 2.0 + eyeMovement * time
70 | let lipY: CGFloat = -mouthMovement / 2.0 + time * mouthMovement
71 |
72 | context.translateBy(x: 50, y: 50)
73 |
74 | // Face Drawing
75 | if showFace {
76 | let facePath = UIBezierPath(ovalIn: CGRect(x: -20, y: -20, width: 40, height: 40))
77 | facePath.lineWidth = scaledLineWidth
78 | facePath.stroke()
79 | facePath.fill()
80 | }
81 |
82 | strokeColor.setFill()
83 |
84 | // Right eye Drawing
85 | context.saveGState()
86 | context.translateBy(x: -8, y: (eyeOffset - 9))
87 |
88 | let rightEyePath = UIBezierPath(ovalIn: CGRect(x: minusHalfLineWidth, y: minusHalfLineWidth, width: scaledLineWidth, height: scaledLineWidth))
89 | rightEyePath.fill()
90 |
91 | context.restoreGState()
92 |
93 | // Left eye Drawing
94 | context.saveGState()
95 | context.translateBy(x: 8, y: (eyeOffset - 9))
96 |
97 | let leftEyePath = UIBezierPath(ovalIn: CGRect(x: minusHalfLineWidth, y: minusHalfLineWidth, width: scaledLineWidth, height: scaledLineWidth))
98 | leftEyePath.fill()
99 |
100 | context.restoreGState()
101 |
102 | // Bezier Drawing
103 | context.saveGState()
104 | context.translateBy(x: 0, y: 5)
105 |
106 | let mouthPath = UIBezierPath(style: self)
107 | mouthPath.move(to: CGPoint(x: -10, y: lipY))
108 | mouthPath.addCurve(to: CGPoint(x: 0, y: 0), controlPoint1: CGPoint(x: -10, y: lipY), controlPoint2: CGPoint(x: -7, y: 0))
109 | mouthPath.addCurve(to: CGPoint(x: 10, y: lipY), controlPoint1: CGPoint(x: 7, y: -0), controlPoint2: CGPoint(x: 10, y: lipY))
110 |
111 | mouthPath.stroke()
112 |
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/EarthIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EarthIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 28/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class EarthIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconLightGreenColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var fillColor: UIColor = .iconLightGreenColor {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var latitudeCount: UInt = 6 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var longitudeCount: UInt = 10 {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var size: CGFloat = 40 {
41 | didSet {
42 | layer.setNeedsDisplay()
43 | }
44 | }
45 |
46 | @IBInspectable public var progress: Bool {
47 | get {
48 | return Bool(value)
49 | }
50 | set {
51 | value = CGFloat(newValue)
52 | }
53 | }
54 |
55 | // MARK: - Drawing methods
56 |
57 | override func draw(time: CGFloat = 0) {
58 | guard let context = UIGraphicsGetCurrentContext() else {
59 | return
60 | }
61 |
62 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
63 | context.scaleBy(x: scale, y: scale)
64 |
65 | strokeColor.setStroke()
66 | fillColor.withAlphaComponent(fillAlpha).setFill()
67 |
68 | context.saveGState()
69 | context.translateBy(x: 50, y: 50)
70 |
71 | // Circle Drawing
72 |
73 | let circlePath = UIBezierPath(ovalIn: CGRect(x: -20, y: -20, width: 40, height: 40))
74 | circlePath.lineWidth = lineWidth
75 | circlePath.stroke()
76 | circlePath.fill()
77 |
78 | // Draw longitudes
79 | for i in 0...longitudeCount {
80 |
81 | let delayedTime = -time + (CGFloat(i) / CGFloat(longitudeCount)) * 2
82 | let offset = delayedTime.constrain(low: 0, high: 1)
83 |
84 | let linePosition: CGFloat = offset.map(min: 0, max: 1, from: 20, to: -20)
85 | let controlPointPosition: CGFloat = offset.map(min: 0, max: 1, from: 11, to: -11)
86 |
87 | let longitudePath = UIBezierPath(style: self)
88 | longitudePath.move(to: CGPoint(x: 0, y: -20))
89 | longitudePath.addCurve(to: CGPoint(x: linePosition, y: 0), controlPoint1: CGPoint(x: controlPointPosition, y: -20), controlPoint2: CGPoint(x: linePosition, y: -11.05))
90 | longitudePath.addCurve(to: CGPoint(x: 0, y: 20), controlPoint1: CGPoint(x: linePosition, y: 11.05), controlPoint2: CGPoint(x: controlPointPosition, y: 20))
91 |
92 | longitudePath.stroke()
93 |
94 | }
95 |
96 | // Draw latitudes
97 | let pi: CGFloat = .pi
98 |
99 | for i in 0...latitudeCount {
100 |
101 | let i = CGFloat(i)
102 | let count = CGFloat(latitudeCount)
103 |
104 | let y = i.map(min: 0, max: count, from: -size / 2.0, to: size / 2.0)
105 | let x = sin(i/count * pi) * size / 2
106 |
107 | let latitudePath = UIBezierPath(style: self)
108 | latitudePath.move(to: CGPoint(x: -x, y: y))
109 | latitudePath.addLine(to: CGPoint(x: x, y: y))
110 | latitudePath.stroke()
111 | }
112 |
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/StarIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StarIcon.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 15/04/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class StarIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconOrangeColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 | @IBInspectable public var fillColor: UIColor = .iconOrangeColor {
22 | didSet {
23 | layer.setNeedsDisplay()
24 | }
25 | }
26 | @IBInspectable public var doubleLines: Bool = true {
27 | didSet {
28 | layer.setNeedsDisplay()
29 | }
30 | }
31 |
32 | @IBInspectable public var animationInsideDirection: Bool = true {
33 | didSet {
34 | layer.setNeedsDisplay()
35 | }
36 | }
37 |
38 | @IBInspectable public var animationCenteredOnCorners: Bool = true {
39 | didSet {
40 | layer.setNeedsDisplay()
41 | }
42 | }
43 |
44 | @IBInspectable public var visible: Bool {
45 | get {
46 | return Bool(value)
47 | }
48 | set {
49 | value = CGFloat(newValue)
50 | }
51 | }
52 |
53 | // MARK: - Drawing methods
54 |
55 | override func draw(time: CGFloat = 0) {
56 | guard time > 0, let context = UIGraphicsGetCurrentContext() else {
57 | return
58 | }
59 |
60 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
61 |
62 | // Variable Declarations
63 | let lineLength: CGFloat = 18.2
64 | let dash: CGFloat = time * lineLength
65 | let doubleDash: CGFloat = 2 * dash
66 | let outerPhase: CGFloat = dash
67 | let gap: CGFloat = (1 - time) * lineLength
68 | let doubleGap: CGFloat = 2 * gap
69 | let innerPhase: CGFloat = lineLength + dash
70 | let varyingGap: CGFloat = doubleLines ? doubleGap : gap
71 | let varyingDash: CGFloat = doubleLines ? doubleDash : dash
72 | let inOutPhase = animationInsideDirection ? outerPhase : innerPhase
73 | let linePhase = animationInsideDirection ? 0 : lineLength
74 |
75 | context.scaleBy(x: scale, y: scale)
76 |
77 | // Path Drawing
78 | let path = UIBezierPath(style: self)
79 | path.move(to: CGPoint(x: 50, y: 27.15))
80 | path.addLine(to: CGPoint(x: 55.58, y: 44.46))
81 | path.addLine(to: CGPoint(x: 73.78, y: 44.42))
82 | path.addLine(to: CGPoint(x: 59.04, y: 55.09))
83 | path.addLine(to: CGPoint(x: 64.69, y: 72.38))
84 | path.addLine(to: CGPoint(x: 50, y: 61.65))
85 | path.addLine(to: CGPoint(x: 35.31, y: 72.38))
86 | path.addLine(to: CGPoint(x: 40.96, y: 55.09))
87 | path.addLine(to: CGPoint(x: 26.22, y: 44.42))
88 | path.addLine(to: CGPoint(x: 44.42, y: 44.46))
89 | path.close()
90 |
91 | strokeColor.setStroke()
92 | fillColor.withAlphaComponent(time * fillAlpha).setFill()
93 |
94 | context.saveGState()
95 |
96 | if time < 1 {
97 | let calculatedDash = animationCenteredOnCorners ? doubleDash : varyingDash
98 | let calculatedGap = animationCenteredOnCorners ? doubleGap : varyingGap
99 | context.setLineDash(phase: animationCenteredOnCorners ? inOutPhase : linePhase, lengths: [
100 | calculatedDash < 0 ? 0 : calculatedDash,
101 | calculatedGap < 0 ? 0 : calculatedGap
102 | ])
103 | }
104 | path.fill()
105 | path.stroke()
106 | context.restoreGState()
107 |
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/PlayPauseIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class PlayPauseIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var width: CGFloat = 10 {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var height: CGFloat = 40 {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var playColor: UIColor = .iconLightGreenColor {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var pauseColor: UIColor = .iconOrangeColor {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var playing: Bool {
41 | get {
42 | return Bool(value)
43 | }
44 | set {
45 | value = CGFloat(newValue)
46 | }
47 | }
48 |
49 | // MARK: - Drawing methods
50 |
51 | override func draw(time: CGFloat = 0) {
52 | guard let context = UIGraphicsGetCurrentContext() else {
53 | return
54 | }
55 |
56 | let strokeColor = UIColor(between: playColor, and: pauseColor, using: colorMode, ratio: time)
57 | strokeColor.setStroke()
58 |
59 | let fillColor = strokeColor.withAlphaComponent(fillAlpha)
60 | fillColor.setFill()
61 |
62 | // Variable Declarations
63 | let invertedTime: CGFloat = 1 - time
64 | let offsetX: CGFloat = width / 2.0
65 | let offsetMinusX: CGFloat = -width / 2.0
66 | let offsetY: CGFloat = height / 2.0
67 | let decreasingOffset: CGFloat = offsetY * time
68 | let decreasingMinusOffset: CGFloat = -decreasingOffset
69 | let offsetMinusY: CGFloat = -height / 2.0
70 | let topPoint = CGPoint(x: offsetX + height / 2.0 * invertedTime, y: -offsetY * time)
71 | let bottomPoint = CGPoint(x: offsetX + height / 2.0 * invertedTime, y: -offsetMinusY * time)
72 |
73 | context.scaleBy(x: scale, y: scale)
74 |
75 | // Right line Drawing
76 | if time > 0 {
77 | context.saveGState()
78 | context.translateBy(x: 60, y: 50)
79 |
80 | let rightLinePath = UIBezierPath(style: self)
81 | rightLinePath.move(to: CGPoint(x: offsetMinusX, y: decreasingOffset))
82 | rightLinePath.addLine(to: CGPoint(x: offsetX, y: decreasingOffset))
83 | rightLinePath.addLine(to: CGPoint(x: offsetX, y: decreasingMinusOffset))
84 | rightLinePath.addLine(to: CGPoint(x: offsetMinusX, y: decreasingMinusOffset))
85 | rightLinePath.addLine(to: CGPoint(x: offsetMinusX, y: decreasingOffset))
86 | rightLinePath.close()
87 |
88 | rightLinePath.stroke()
89 | rightLinePath.fill()
90 |
91 | context.restoreGState()
92 | }
93 |
94 | // Left line Drawing
95 | context.saveGState()
96 | context.translateBy(x: 40, y: 50)
97 |
98 | let leftLinePath = UIBezierPath(style: self)
99 | leftLinePath.move(to: CGPoint(x: offsetMinusX, y: offsetY))
100 | leftLinePath.addLine(to: bottomPoint)
101 | leftLinePath.addLine(to: topPoint)
102 | leftLinePath.addLine(to: CGPoint(x: offsetMinusX, y: offsetMinusY))
103 | leftLinePath.addLine(to: CGPoint(x: offsetMinusX, y: offsetY))
104 | leftLinePath.close()
105 |
106 | leftLinePath.stroke()
107 | leftLinePath.fill()
108 |
109 | context.restoreGState()
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/Icons.playground/Pages/Showcase.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | //:
2 | //: # Animated icons
3 | //:
4 | //: *Designed and developed by Matěj K. Jirásek ([mkj.is](http://mkj.is))*
5 | //:
6 | //: [](https://github.com/Carthage/Carthage)
7 | //: [](https://codeclimate.com/github/mkj-is/MKJIcons)
8 | //:
9 | //: Full documentation is available here:
10 | //:
11 | //: - [**Go to next chapter.**](@next)
12 | //:
13 | //: -----
14 | //:
15 | //: 
16 | //:
17 | //: An icon set usable as an iOS framework. This first documentation page
18 | //: serves as an reference and showcase of all available icons.
19 | //:
20 | //: The icons feature:
21 | //:
22 | //: - Vector rendering.
23 | //: - Independent on size.
24 | //: - Colours can be set to your liking.
25 | //: - Line width, caps and joins can all be configured.
26 | //: - Animation duration and color changes can be fully configured too.
27 | //: - Using the playground you can export PNG sequences if you like bitmaps too.
28 | //: - Each icon has its setting for most values.
29 | //: - Icons can be used as buttons or checkboxes,
30 | //: they are controls and you can bind actions to them
31 | //: and listen to “value changed” event.
32 | //: - The icons are designable in the interface builder, so you can view how they will
33 | //: look in the final application and design them in Xcode!
34 | //:
35 | //: **You need to have the assistant editor with timeline open to view the icons.
36 | //: If you click them, then they will animate. Some of them are invisible
37 | //: by default. Do not forget to click the empty places too!**
38 | //:
39 |
40 | // We need to import basic frameworks so this example can work
41 | import UIKit
42 | import PlaygroundSupport
43 |
44 | // These are all the icons available
45 | let checkmark = CheckmarkIcon(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
46 | let burger = BurgerIcon(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
47 | let heart = HeartIcon(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
48 | let star = StarIcon(frame: CGRect(x: 300, y: 0, width: 100, height: 100))
49 | let plus = PlusMinusIcon(frame: CGRect(x: 0, y: 100, width: 100, height: 100))
50 | let settings = SettingsIcon(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
51 | let pin = DropPinIcon(frame: CGRect(x: 200, y: 100, width: 100, height: 100))
52 | let play = PlayPauseIcon(frame: CGRect(x: 300, y: 100, width: 100, height: 100))
53 | let stop = PlayStopIcon(frame: CGRect(x: 0, y: 200, width: 100, height: 100))
54 | let smile = SmileIcon(frame: CGRect(x: 100, y: 200, width: 100, height: 100))
55 | let fingerprint = FingerprintIcon(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
56 | let clip = PaperclipIcon(frame: CGRect(x: 300, y: 200, width: 100, height: 100))
57 | let wave = SoundwaveIcon(frame: CGRect(x: 0, y: 300, width: 100, height: 100))
58 | let bike = BikeIcon(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
59 | let earth = EarthIcon(frame: CGRect(x: 200, y: 300, width: 100, height: 100))
60 | let textAlign = TextAlignIcon(frame: CGRect(x: 300, y: 300, width: 100, height: 100))
61 | let ellipsis = EllipsisIcon(frame: CGRect(x: 0, y: 400, width: 100, height: 100))
62 |
63 | // We create a view to contain all the icons
64 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 500))
65 |
66 | // Then we add them to the large parent view
67 | let icons = [
68 | checkmark, burger, heart, star, plus,
69 | settings, pin, play, stop, smile,
70 | fingerprint, clip, wave, bike, earth,
71 | textAlign, ellipsis
72 | ]
73 | icons.forEach(view.addSubview)
74 |
75 | // At last we assign the parent view with the icons to assistant editor
76 | PlaygroundPage.current.liveView = view
77 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/SettingsIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Checkmark.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 31/03/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class SettingsIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var primaryColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var secondaryColor: UIColor = .lightGray {
23 | didSet {
24 | layer.setNeedsDisplay()
25 | }
26 | }
27 |
28 | @IBInspectable public var handleSize: CGFloat = 6 {
29 | didSet {
30 | layer.setNeedsDisplay()
31 | }
32 | }
33 |
34 | @IBInspectable public var roundedHandle: Bool = true {
35 | didSet {
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | @IBInspectable public var changed: Bool {
41 | get {
42 | return Bool(value)
43 | }
44 | set {
45 | value = CGFloat(newValue)
46 | }
47 | }
48 |
49 | // MARK: - Drawing methods
50 |
51 | override func draw(time: CGFloat = 0) {
52 | guard let context = UIGraphicsGetCurrentContext() else {
53 | return
54 | }
55 |
56 | let strokeColor = UIColor(between: primaryColor, and: secondaryColor, using: colorMode, ratio: time)
57 | strokeColor.setStroke()
58 | let fillColor = strokeColor.withAlphaComponent(fillAlpha)
59 | fillColor.setFill()
60 |
61 | context.scaleBy(x: scale, y: scale)
62 |
63 | // Slider 1 Drawing
64 | context.saveGState()
65 | context.translateBy(x: 50, y: 50)
66 | context.rotate(by: -180 * .pi / 180)
67 |
68 | let slider1Rect = CGRect(x: -10, y: -25, width: 20, height: 50)
69 | context.saveGState()
70 | UIRectClip(slider1Rect)
71 | context.translateBy(x: slider1Rect.origin.x, y: slider1Rect.origin.y)
72 |
73 | drawSlider(time: time)
74 | context.restoreGState()
75 |
76 | context.restoreGState()
77 |
78 | // Slider 2 Drawing
79 | context.saveGState()
80 | context.translateBy(x: 65, y: 50)
81 |
82 | let slider2Rect = CGRect(x: -10, y: -25, width: 20, height: 50)
83 | context.saveGState()
84 | UIRectClip(slider2Rect)
85 | context.translateBy(x: slider2Rect.origin.x, y: slider2Rect.origin.y)
86 |
87 | drawSlider(time: time)
88 | context.restoreGState()
89 |
90 | context.restoreGState()
91 |
92 | // Slider 3 Drawing
93 | context.saveGState()
94 | context.translateBy(x: 35, y: 50)
95 |
96 | let slider3Rect = CGRect(x: -10, y: -25, width: 20, height: 50)
97 | context.saveGState()
98 | UIRectClip(slider3Rect)
99 | context.translateBy(x: slider3Rect.origin.x, y: slider3Rect.origin.y)
100 |
101 | drawSlider(time: time)
102 | context.restoreGState()
103 |
104 | context.restoreGState()
105 | }
106 |
107 | func drawSlider(time: CGFloat = 1) {
108 | guard let context = UIGraphicsGetCurrentContext() else {
109 | return
110 | }
111 |
112 | // Variable Declarations
113 | let handlePosition: CGFloat = 12 + time * 26
114 | let halfHandleSize: CGFloat = handleSize / 2.0
115 | let negativeHalfHandleSize: CGFloat = -halfHandleSize
116 | let longLineLength: CGFloat = -halfHandleSize + time * 26
117 | let shortLineLength: CGFloat = -halfHandleSize + (1 - time) * 26
118 | let cornerRadius: CGFloat = roundedHandle ? halfHandleSize : 0
119 |
120 | // Handle Drawing
121 | context.saveGState()
122 | context.translateBy(x: 10, y: handlePosition)
123 |
124 | let handlePath = UIBezierPath(roundedRect: CGRect(x: negativeHalfHandleSize, y: negativeHalfHandleSize, width: handleSize, height: handleSize), cornerRadius: cornerRadius)
125 |
126 | handlePath.lineWidth = scaledLineWidth
127 | handlePath.lineCapStyle = lineCap
128 | handlePath.lineJoinStyle = lineJoin
129 |
130 | handlePath.fill()
131 | handlePath.stroke()
132 |
133 | context.restoreGState()
134 |
135 | // Top line Drawing
136 | let topLinePath = UIBezierPath(style: self)
137 | topLinePath.move(to: CGPoint(x: 10, y: 5))
138 | topLinePath.addLine(to: CGPoint(x: 10, y: (longLineLength + 12)))
139 |
140 | topLinePath.stroke()
141 |
142 | // Bottom line Drawing
143 | context.saveGState()
144 | context.translateBy(x: 10, y: 45)
145 | context.rotate(by: -180 * .pi / 180)
146 |
147 | let bottomLine = UIBezierPath(style: self)
148 | bottomLine.move(to: CGPoint(x: 0, y: 0))
149 | bottomLine.addLine(to: CGPoint(x: 0, y: (shortLineLength + 7)))
150 |
151 | bottomLine.stroke()
152 |
153 | context.restoreGState()
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/DropPinIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeartIcon.swift
3 | //
4 | //
5 | // Created by Matěj Jirásek on 3/04/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class DropPinIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 | @IBInspectable public var fillColor: UIColor = .iconDefault {
22 | didSet {
23 | layer.setNeedsDisplay()
24 | }
25 | }
26 | @IBInspectable public var circle: Bool = true {
27 | didSet {
28 | layer.setNeedsDisplay()
29 | }
30 | }
31 |
32 | @IBInspectable public var visible: Bool {
33 | get {
34 | return Bool(value)
35 | }
36 | set {
37 | value = CGFloat(newValue)
38 | }
39 | }
40 |
41 | // MARK: - Drawing methods
42 |
43 | override func draw(time: CGFloat = 0) {
44 | guard time > 0, let context = UIGraphicsGetCurrentContext() else {
45 | return
46 | }
47 |
48 | strokeColor.setStroke()
49 | fillColor.withAlphaComponent(time * fillAlpha).setFill()
50 |
51 | // Variable Declarations
52 | let circleLineLength: CGFloat = 20 * .pi * time
53 | let pinLineLength: CGFloat = time * 154
54 |
55 | context.scaleBy(x: scale, y: scale)
56 | context.translateBy(x: 50, y: 40)
57 |
58 | // Fill Drawing
59 | let fillPath = UIBezierPath(style: self)
60 |
61 | if circle {
62 | fillPath.move(to: CGPoint(x: 0, y: -10))
63 | fillPath.addCurve(to: CGPoint(x: -10, y: 0), controlPoint1: CGPoint(x: -5, y: -10), controlPoint2: CGPoint(x: -10, y: -5))
64 | fillPath.addCurve(to: CGPoint(x: -10, y: 0), controlPoint1: CGPoint(x: -10, y: 0), controlPoint2: CGPoint(x: -10, y: 0))
65 | fillPath.addCurve(to: CGPoint(x: 0, y: 10), controlPoint1: CGPoint(x: -10, y: 5), controlPoint2: CGPoint(x: -5, y: 10))
66 | fillPath.addCurve(to: CGPoint(x: 10, y: 0), controlPoint1: CGPoint(x: 5, y: 10), controlPoint2: CGPoint(x: 10, y: 5))
67 | fillPath.addCurve(to: CGPoint(x: 0, y: -10), controlPoint1: CGPoint(x: 10, y: -5), controlPoint2: CGPoint(x: 5, y: -10))
68 | fillPath.close()
69 | }
70 |
71 | fillPath.move(to: CGPoint(x: 0, y: 40))
72 | fillPath.addCurve(to: CGPoint(x: -20, y: 0), controlPoint1: CGPoint(x: -20, y: 15), controlPoint2: CGPoint(x: -20, y: 10))
73 | fillPath.addCurve(to: CGPoint(x: 0, y: -20), controlPoint1: CGPoint(x: -20, y: -10), controlPoint2: CGPoint(x: -10, y: -20))
74 | fillPath.addCurve(to: CGPoint(x: 20, y: 0), controlPoint1: CGPoint(x: 10, y: -20), controlPoint2: CGPoint(x: 20, y: -10))
75 | fillPath.addCurve(to: CGPoint(x: 0, y: 40), controlPoint1: CGPoint(x: 20, y: 10), controlPoint2: CGPoint(x: 20, y: 15))
76 | fillPath.close()
77 |
78 | fillPath.fill()
79 |
80 | if circle {
81 | // Circle Drawing
82 | context.saveGState()
83 | context.rotate(by: -180 * .pi / 180)
84 |
85 | let circlePath = UIBezierPath(style: self)
86 | circlePath.move(to: CGPoint(x: 0, y: -10))
87 | circlePath.addCurve(to: CGPoint(x: 10, y: 0), controlPoint1: CGPoint(x: 5, y: -10), controlPoint2: CGPoint(x: 10, y: -5))
88 | circlePath.addCurve(to: CGPoint(x: 0, y: 10), controlPoint1: CGPoint(x: 10, y: 5), controlPoint2: CGPoint(x: 5, y: 10))
89 | circlePath.addCurve(to: CGPoint(x: -10, y: 0), controlPoint1: CGPoint(x: -5, y: 10), controlPoint2: CGPoint(x: -10, y: 5))
90 | circlePath.addCurve(to: CGPoint(x: 0, y: -10), controlPoint1: CGPoint(x: -10, y: -5), controlPoint2: CGPoint(x: -5, y: -10))
91 | circlePath.close()
92 |
93 | if time < 1 {
94 | context.setLineDash(phase: 0, lengths: [circleLineLength, 400])
95 | }
96 | circlePath.stroke()
97 |
98 | context.restoreGState()
99 | }
100 |
101 | // Drop Drawing
102 |
103 | let dropPath = UIBezierPath(style: self)
104 | dropPath.move(to: CGPoint(x: 0, y: 40))
105 | dropPath.addCurve(to: CGPoint(x: -20, y: 0), controlPoint1: CGPoint(x: -20, y: 15), controlPoint2: CGPoint(x: -20, y: 10))
106 | dropPath.addCurve(to: CGPoint(x: 0, y: -20), controlPoint1: CGPoint(x: -20, y: -10), controlPoint2: CGPoint(x: -10, y: -20))
107 | dropPath.addCurve(to: CGPoint(x: 20, y: 0), controlPoint1: CGPoint(x: 10, y: -20), controlPoint2: CGPoint(x: 20, y: -10))
108 | dropPath.addCurve(to: CGPoint(x: 0, y: 40), controlPoint1: CGPoint(x: 20, y: 10), controlPoint2: CGPoint(x: 20, y: 15))
109 | dropPath.close()
110 |
111 | if time < 1 {
112 | context.setLineDash(phase: 0, lengths: [pinLineLength, 154])
113 | }
114 | dropPath.stroke()
115 |
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/BikeIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BikeIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 27/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class BikeIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconOrangeColor {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var visible: Bool {
23 | get {
24 | return Bool(value)
25 | }
26 | set {
27 | value = CGFloat(newValue)
28 | }
29 | }
30 |
31 | // MARK: - Drawing methods
32 |
33 | override func draw(time: CGFloat = 0) {
34 | guard time != 0, let context = UIGraphicsGetCurrentContext() else {
35 | return
36 | }
37 |
38 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
39 | context.scaleBy(x: scale, y: scale)
40 |
41 | strokeColor.setStroke()
42 |
43 | // Variable Declarations
44 | let firstDraw: CGFloat = time * 3
45 | let one: CGFloat = firstDraw < 0 ? 0 : (firstDraw > 1 ? 1 : firstDraw)
46 | let secondDraw: CGFloat = time * 3 - 1
47 | let two: CGFloat = secondDraw < 0 ? 0 : (secondDraw > 1 ? 1 : secondDraw)
48 | let thirdDraw: CGFloat = time * 3 - 2
49 | let three: CGFloat = thirdDraw < 0 ? 0 : (thirdDraw > 1 ? 1 : thirdDraw)
50 |
51 | let frameLine: CGFloat = two * 88
52 | let bikeLine: CGFloat = one * 69
53 | let barLine: CGFloat = three * 33
54 | let seatLine: CGFloat = three * 38
55 |
56 | // First wheel
57 | context.saveGState()
58 | context.translateBy(x: 29.5, y: 64.5)
59 | context.rotate(by: 110 * .pi / 180)
60 |
61 | let firstWheel = UIBezierPath(style: self)
62 | firstWheel.move(to: CGPoint(x: -11, y: 0))
63 | firstWheel.addCurve(to: CGPoint(x: 0, y: 11), controlPoint1: CGPoint(x: -11, y: 6.08), controlPoint2: CGPoint(x: -6.08, y: 11))
64 | firstWheel.addCurve(to: CGPoint(x: 11, y: 0), controlPoint1: CGPoint(x: 6.08, y: 11), controlPoint2: CGPoint(x: 11, y: 6.08))
65 | firstWheel.addCurve(to: CGPoint(x: 0, y: -11), controlPoint1: CGPoint(x: 11, y: -6.08), controlPoint2: CGPoint(x: 6.08, y: -11))
66 | firstWheel.addCurve(to: CGPoint(x: -11, y: 0), controlPoint1: CGPoint(x: -6.08, y: -11), controlPoint2: CGPoint(x: -11, y: -6.08))
67 | firstWheel.close()
68 |
69 | context.saveGState()
70 | context.setLineDash(phase: 0, lengths: [bikeLine, 100])
71 | firstWheel.stroke()
72 |
73 | context.restoreGState()
74 | context.restoreGState()
75 |
76 | // Second wheel
77 | context.saveGState()
78 | context.translateBy(x: 70.5, y: 64.5)
79 | context.scaleBy(x: -1, y: 1)
80 | context.rotate(by: -110 * .pi / 180)
81 |
82 | let secondWheel = UIBezierPath(style: self)
83 | secondWheel.move(to: CGPoint(x: 11, y: 0))
84 | secondWheel.addCurve(to: CGPoint(x: 0, y: 11), controlPoint1: CGPoint(x: 11, y: 6.08), controlPoint2: CGPoint(x: 6.08, y: 11))
85 | secondWheel.addCurve(to: CGPoint(x: -11, y: 0), controlPoint1: CGPoint(x: -6.08, y: 11), controlPoint2: CGPoint(x: -11, y: 6.08))
86 | secondWheel.addCurve(to: CGPoint(x: 0, y: -11), controlPoint1: CGPoint(x: -11, y: -6.08), controlPoint2: CGPoint(x: -6.08, y: -11))
87 | secondWheel.addCurve(to: CGPoint(x: 11, y: 0), controlPoint1: CGPoint(x: 6.08, y: -11), controlPoint2: CGPoint(x: 11, y: -6.08))
88 | secondWheel.close()
89 |
90 | context.saveGState()
91 | context.setLineDash(phase: 0, lengths: [bikeLine, 100])
92 | secondWheel.stroke()
93 | context.restoreGState()
94 |
95 | context.restoreGState()
96 |
97 | // Frame
98 | if two > 0 {
99 | let framePath = UIBezierPath(style: self)
100 | framePath.move(to: CGPoint(x: 61.5, y: 46.5))
101 | framePath.addLine(to: CGPoint(x: 37.5, y: 46.5))
102 | framePath.addLine(to: CGPoint(x: 53.5, y: 65.5))
103 | framePath.addLine(to: CGPoint(x: 70.5, y: 65.5))
104 | framePath.addLine(to: CGPoint(x: 61.5, y: 46.5))
105 | framePath.close()
106 |
107 | context.saveGState()
108 | context.setLineDash(phase: 0, lengths: [frameLine, 400])
109 | framePath.stroke()
110 | context.restoreGState()
111 | }
112 |
113 | // Seat and bars
114 | if three > 0 {
115 | let bars = UIBezierPath(style: self)
116 | bars.move(to: CGPoint(x: 30.5, y: 63.5))
117 | bars.addLine(to: CGPoint(x: 39.5, y: 41.5))
118 | bars.addLine(to: CGPoint(x: 30.5, y: 41.5))
119 |
120 | context.saveGState()
121 | context.setLineDash(phase: 0, lengths: [barLine, 100])
122 | bars.stroke()
123 | context.restoreGState()
124 |
125 | let seat = UIBezierPath(style: self)
126 | seat.move(to: CGPoint(x: 53.5, y: 65.5))
127 | seat.addLine(to: CGPoint(x: 64.5, y: 38.5))
128 | seat.addLine(to: CGPoint(x: 56.5, y: 38.5))
129 |
130 | context.saveGState()
131 | context.setLineDash(phase: 0, lengths: [seatLine, 100])
132 | seat.stroke()
133 | context.restoreGState()
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Main classes/AnimatedIcon.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @IBDesignable
4 | public class AnimatedIcon: UIControl {
5 |
6 | // MARK: - Inspectable properties
7 |
8 | @IBInspectable public var animationDuration: Double = 0.4
9 |
10 | @IBInspectable public var lineWidth: CGFloat = 2.0 {
11 | didSet {
12 | layer.setNeedsDisplay()
13 | }
14 | }
15 |
16 | @IBInspectable public var fillAlpha: CGFloat = 0.5 {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var animationRepeat: Bool = false {
23 | didSet {
24 | if animationRepeat {
25 | animate(to: CGFloat(!Bool(value)))
26 | }
27 | layer.setNeedsDisplay()
28 | }
29 | }
30 |
31 | @IBInspectable public var animationAutoreverses: Bool = true {
32 | didSet {
33 | if animationRepeat {
34 | animate(to: CGFloat(!Bool(value)))
35 | }
36 | layer.setNeedsDisplay()
37 | }
38 | }
39 |
40 | // MARK: - Properties
41 |
42 | public var colorMode: UIColorMode = .hsb {
43 | didSet {
44 | layer.setNeedsDisplay()
45 | }
46 | }
47 | public var lineCap: CGLineCap = .round {
48 | didSet {
49 | layer.setNeedsDisplay()
50 | }
51 | }
52 | public var lineJoin: CGLineJoin = .round {
53 | didSet {
54 | layer.setNeedsDisplay()
55 | }
56 | }
57 |
58 | public var timingFunctionName: CAMediaTimingFunctionName = .easeInEaseOut
59 |
60 | public var value: CGFloat = 0 {
61 | didSet {
62 | if oldValue != value {
63 | animate(to: value)
64 | }
65 |
66 | if isEnabled {
67 | self.sendActions(for: .valueChanged)
68 | }
69 |
70 | layer.setNeedsDisplay()
71 | }
72 | }
73 |
74 | // MARK: - Internal properties
75 |
76 | var scale: CGFloat {
77 | return min(frame.size.width, frame.size.height) / 100
78 | }
79 |
80 | var scaledLineWidth: CGFloat {
81 | return lineWidth / scale
82 | }
83 |
84 | // MARK: - Initialization
85 |
86 | override public init(frame: CGRect) {
87 | super.init(frame: frame)
88 | backgroundColor = .clear
89 | setContentsScale()
90 | }
91 |
92 | required public init?(coder aDecoder: NSCoder) {
93 | super.init(coder: aDecoder)
94 | setContentsScale()
95 | }
96 |
97 | // MARK: - Internal helper methods
98 |
99 | func setContentsScale() {
100 | layer.setNeedsDisplay()
101 |
102 | let scale = UIScreen.main.scale
103 | layer.contentsScale = scale
104 | contentScaleFactor = scale
105 | }
106 |
107 | // MARK: - Drawing methods
108 |
109 | override public class var layerClass: AnyClass {
110 | return AnimationLayer.self
111 | }
112 |
113 | override public func draw(_ layer: CALayer, in ctx: CGContext) {
114 | UIGraphicsPushContext(ctx)
115 | if let layer = layer as? AnimationLayer {
116 | draw(time: layer.value)
117 | }
118 | UIGraphicsPopContext()
119 | }
120 |
121 | public func image(at: CGFloat = 0) -> UIImage {
122 | UIGraphicsBeginImageContextWithOptions(frame.size, false, contentScaleFactor)
123 | defer {
124 | UIGraphicsEndImageContext()
125 | }
126 | draw(time: at)
127 | return UIGraphicsGetImageFromCurrentImageContext()!
128 | }
129 |
130 | /**
131 | Draws the content of the icons. Needs to be overriden in subclasses of `AnimatedIcon`.
132 |
133 | - Parameter time: The position of animation, start of the animation will be 0 and the end will be 1. If the animation is reverted the value will be changing from 1 to 0.
134 | */
135 | func draw(time: CGFloat = 0) {
136 | fatalError("Method must be overriden in subclasses. Do not instantiate this class directly.")
137 | }
138 |
139 | public func animate(to goal: CGFloat) {
140 | if let layer = layer as? AnimationLayer {
141 | #if TARGET_INTERFACE_BUILDER
142 | layer.value = goal
143 | layer.setNeedsDisplay()
144 | #else
145 |
146 | layer.removeAllAnimations()
147 |
148 | let timingFunction = CAMediaTimingFunction(name: timingFunctionName)
149 | let animation = CABasicAnimation(keyPath: "value")
150 | animation.duration = animationDuration
151 | animation.fillMode = .both
152 | animation.timingFunction = timingFunction
153 | animation.fromValue = layer.value
154 | animation.toValue = goal
155 |
156 | if animationRepeat {
157 | animation.repeatCount = .infinity
158 | animation.autoreverses = animationAutoreverses
159 | }
160 |
161 | layer.add(animation, forKey: nil)
162 |
163 | CATransaction.begin()
164 | CATransaction.setDisableActions(true)
165 | layer.value = goal
166 | CATransaction.commit()
167 | #endif
168 | }
169 | }
170 |
171 | // MARK: - Interaction
172 |
173 | public override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
174 | if isEnabled {
175 | value = (value == 0 ? 1 : 0)
176 | }
177 | }
178 |
179 | // MARK: - Dark mode support
180 |
181 | public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
182 | if #available(iOS 12.0, tvOS 10.0, *), traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
183 | layer.setNeedsDisplay()
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Animated icons
3 |
4 | *Designed and developed by Matěj K. Jirásek ([mkj.is](http://mkj.is))*
5 |
6 | Full documentation is available here:
7 |
8 | 
9 |
10 | ## Table of contents
11 |
12 | * [Installation](#installation)
13 | * [Showcase](#showcase)
14 | * [Basics](#basics)
15 | * [Export](#export)
16 |
17 | ## Intallation
18 |
19 | There minimal requirements needed to be met to install this library:
20 |
21 | - iOS 8 or tvOS 9
22 | - Xcode 11.0
23 | - Swift 5.0
24 |
25 | To install use Xcode 11 and add a package or manually add following line to your `Package.swift` file:
26 |
27 | ```swift
28 | .package(url: "https://github.com/mkj-is/MKJIcons.git", from: "0.3.0")
29 | ```
30 |
31 | ## Showcase
32 |
33 | An icon set usable as an iOS framework. This first documentation page
34 | serves as an reference and showcase of all available icons.
35 |
36 | The icons feature:
37 |
38 | - Vector rendering.
39 | - Independent on size.
40 | - Colours can be set to your liking.
41 | - Line width, caps and joins can all be configured.
42 | - Animation duration and color changes can be fully configured too.
43 | - Using the playground you can export PNG sequences if you like bitmaps too.
44 | - Each icon has its setting for most values.
45 | - Icons can be used as buttons or checkboxes,
46 | they are controls and you can bind actions to them
47 | and listen to “value changed” event.
48 | - The icons are designable in the interface builder, so you can view how they will
49 | look in the final application and design them in Xcode!
50 |
51 | **You need to have the assistant editor with timeline open to view the icons.
52 | If you click them, then they will animate. Some of them are invisible
53 | by default. Do not forget to click the empty places too!**
54 |
55 |
56 | ```swift
57 | // We need to import basic frameworks so this example can work
58 | import UIKit
59 | import XCPlayground
60 |
61 | // These are all the icons available
62 | let checkmark = CheckmarkIcon(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
63 | let burger = BurgerIcon(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
64 | let heart = HeartIcon(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
65 | let star = StarIcon(frame: CGRect(x: 300, y: 0, width: 100, height: 100))
66 | let plus = PlusMinusIcon(frame: CGRect(x: 0, y: 100, width: 100, height: 100))
67 | let settings = SettingsIcon(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
68 | let pin = DropPinIcon(frame: CGRect(x: 200, y: 100, width: 100, height: 100))
69 | let play = PlayPauseIcon(frame: CGRect(x: 300, y: 100, width: 100, height: 100))
70 | let stop = PlayStopIcon(frame: CGRect(x: 0, y: 200, width: 100, height: 100))
71 | let smile = SmileIcon(frame: CGRect(x: 100, y: 200, width: 100, height: 100))
72 | let fingerprint = FingerprintIcon(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
73 | let clip = PaperclipIcon(frame: CGRect(x: 300, y: 200, width: 100, height: 100))
74 | let wave = SoundwaveIcon(frame: CGRect(x: 0, y: 300, width: 100, height: 100))
75 | let bike = BikeIcon(frame: CGRect(x: 100, y: 300, width: 100, height: 100))
76 | let earth = EarthIcon(frame: CGRect(x: 200, y: 300, width: 100, height: 100))
77 | let textAlign = TextAlignIcon(frame: CGRect(x: 300, y: 300, width: 100, height: 100))
78 |
79 | // We create a view to contain all the icons
80 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
81 |
82 | // Then we add them to the large parent view
83 | view.addSubview(checkmark)
84 | view.addSubview(burger)
85 | view.addSubview(heart)
86 | view.addSubview(star)
87 | view.addSubview(plus)
88 | view.addSubview(settings)
89 | view.addSubview(pin)
90 | view.addSubview(play)
91 | view.addSubview(stop)
92 | view.addSubview(smile)
93 | view.addSubview(fingerprint)
94 | view.addSubview(clip)
95 | view.addSubview(wave)
96 | view.addSubview(bike)
97 | view.addSubview(earth)
98 | view.addSubview(textAlign)
99 |
100 | // At last we assign the parent view with the icons to assistant editor
101 | XCPlaygroundPage.currentPage.liveView = view
102 | ```
103 |
104 | ## Basics
105 |
106 | This chapter shows how to configure the icon style and appearance.
107 |
108 | Properties listed below can be changed for all the icons, but many of them have much more settings. Also,
109 | these basic values can be set using `UIAppearance` on the application start. If you choose to use this way,
110 | then all the icons created after will inherit these properties.
111 |
112 | And the best thing is, that the icons are `IBDesignable`. That means if you add the to your `.xib` or `.storyboard`,
113 | you can see how they will look in your application and you can prototype the user interface really fast.
114 |
115 | ```swift
116 | // We need to import basic frameworks so this example can work
117 | import UIKit
118 | import XCPlayground
119 |
120 | // Then we create the icon
121 | let icon = BikeIcon(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
122 |
123 | // We can set the line parameters
124 | icon.lineCap = .Round
125 | icon.lineJoin = .Round
126 | icon.lineWidth = 6
127 |
128 | // We make the icon to animate longer so we can see the animation in more detail
129 | icon.animationDuration = 2
130 |
131 | // If you animate using HSB the animation will be really colorful
132 | // (Or you can of course stock with RGB, if you are conservative)
133 | icon.colorMode = .HSB
134 |
135 | // We make the icon visible by default, the icon will animate at the beginning!
136 | icon.visible = true
137 |
138 | // Then we assign the icon to assistant editor
139 | XCPlaygroundPage.currentPage.liveView = icon
140 | ```
141 |
142 | ## Export
143 |
144 | This chapter shows us how to export bitmap image sequences.
145 |
146 | In the framework there is a special class for exporting images
147 | and their sequences from icons. You assign the icon to the exporter
148 | and then save the result and that is all!
149 |
150 | **If you are view this documentation in the playground and want to export the icons, then you need to have
151 | *Shared Playground Data* folder in your user *Documents* folder.**
152 |
153 | ```swift
154 | import UIKit
155 | import XCPlayground
156 |
157 | // We create the icon which will be 100x100 pixels
158 | let icon = CheckmarkIcon(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
159 |
160 | // Then we tell where we would like the sequence to be stored
161 | let folder = XCPlaygroundSharedDataDirectoryURL
162 | .URLByAppendingPathComponent("checkmark_forward")
163 |
164 | // We can tell the exporter how many frames the animation has
165 | let frameCount = 50
166 |
167 | // Also, there is an option to export animation going once forward,
168 | // once backward or forward and back in one export
169 | let direction = AnimatedIconExporterDirection.ForwardAndBack
170 |
171 | // Then we create the exporter and save the result!
172 | let exporter = AnimatedIconExporter(icon: icon, folder: folder, direction: direction, count: frameCount)
173 |
174 | exporter.save()
175 | ```
176 |
--------------------------------------------------------------------------------
/Icons.playground/Sources/Icons/FingerprintIcon.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FingerprintIcon.swift
3 | // MKJIcons
4 | //
5 | // Created by Matěj Jirásek on 26/04/16.
6 | // Copyright © 2016 Matěj Kašpar Jirásek. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @IBDesignable
12 | public class FingerprintIcon: AnimatedIcon {
13 |
14 | // MARK: - Inspectable properties
15 |
16 | @IBInspectable public var strokeColor: UIColor = .iconDefault {
17 | didSet {
18 | layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | @IBInspectable public var visible: Bool {
23 | get {
24 | return Bool(value)
25 | }
26 | set {
27 | value = CGFloat(newValue)
28 | }
29 | }
30 |
31 | // MARK: - Drawing methods
32 |
33 | override func draw(time: CGFloat = 0) {
34 | guard time > 0, let context = UIGraphicsGetCurrentContext() else {
35 | return
36 | }
37 |
38 | context.clear(CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
39 | context.scaleBy(x: scale, y: scale)
40 |
41 | // Variable Declarations
42 | let line1Dash: CGFloat = time * 14
43 | let line2Dash: CGFloat = time * 13
44 | let line3Dash: CGFloat = time * 49
45 | let line4Dash: CGFloat = time * 19
46 | let line5Dash: CGFloat = time * 53
47 | let line6Dash: CGFloat = time * 48
48 | let line7Dash: CGFloat = time * 31
49 | let line8Dash: CGFloat = time * 20
50 | let line9Dash: CGFloat = time * 55
51 | let line10Dash: CGFloat = time * 4
52 | let line11Dash: CGFloat = time * 6
53 |
54 | strokeColor.setStroke()
55 |
56 | // Bezier 3 Drawing
57 | let bezier3Path = UIBezierPath(style: self)
58 | bezier3Path.move(to: CGPoint(x: 66, y: 55.6))
59 | bezier3Path.addCurve(to: CGPoint(x: 59.9, y: 50.17), controlPoint1: CGPoint(x: 66, y: 55.6), controlPoint2: CGPoint(x: 61.53, y: 54.26))
60 | bezier3Path.addCurve(to: CGPoint(x: 45.98, y: 42.3), controlPoint1: CGPoint(x: 58.28, y: 46.08), controlPoint2: CGPoint(x: 54.14, y: 40.19))
61 | bezier3Path.addCurve(to: CGPoint(x: 38.82, y: 47.69), controlPoint1: CGPoint(x: 43.08, y: 43.17), controlPoint2: CGPoint(x: 40.28, y: 44.95))
62 | bezier3Path.addCurve(to: CGPoint(x: 37.58, y: 57.61), controlPoint1: CGPoint(x: 37.36, y: 50.44), controlPoint2: CGPoint(x: 36.75, y: 54.6))
63 | bezier3Path.addCurve(to: CGPoint(x: 34.93, y: 65.68), controlPoint1: CGPoint(x: 38.99, y: 62.72), controlPoint2: CGPoint(x: 37.52, y: 64.84))
64 |
65 | context.saveGState()
66 | context.setLineDash(phase: 0, lengths: [line9Dash, 300])
67 | bezier3Path.stroke()
68 | context.restoreGState()
69 |
70 | // Bezier 4 Drawing
71 | let bezier4Path = UIBezierPath(style: self)
72 | bezier4Path.move(to: CGPoint(x: 37.05, y: 69.57))
73 | bezier4Path.addCurve(to: CGPoint(x: 41.82, y: 55.64), controlPoint1: CGPoint(x: 41.75, y: 68.04), controlPoint2: CGPoint(x: 43.72, y: 64.65))
74 | bezier4Path.addCurve(to: CGPoint(x: 46.98, y: 45.96), controlPoint1: CGPoint(x: 40.93, y: 51.42), controlPoint2: CGPoint(x: 42.98, y: 47.15))
75 | bezier4Path.addCurve(to: CGPoint(x: 56.29, y: 51.32), controlPoint1: CGPoint(x: 50.97, y: 44.77), controlPoint2: CGPoint(x: 55.15, y: 47.16))
76 | bezier4Path.addCurve(to: CGPoint(x: 64.48, y: 60.26), controlPoint1: CGPoint(x: 56.83, y: 53.54), controlPoint2: CGPoint(x: 58.85, y: 56.94))
77 |
78 | context.saveGState()
79 | context.setLineDash(phase: 0, lengths: [line5Dash, 300])
80 | bezier4Path.stroke()
81 | context.restoreGState()
82 |
83 | // Bezier 5 Drawing
84 | let bezier5Path = UIBezierPath(style: self)
85 | bezier5Path.move(to: CGPoint(x: 61.43, y: 67.24))
86 | bezier5Path.addCurve(to: CGPoint(x: 49.06, y: 53.48), controlPoint1: CGPoint(x: 59.7, y: 65.45), controlPoint2: CGPoint(x: 50.86, y: 60))
87 |
88 | context.saveGState()
89 | context.setLineDash(phase: 0, lengths: [line4Dash, 300])
90 | bezier5Path.stroke()
91 | context.restoreGState()
92 |
93 | // Bezier 7 Drawing
94 | let bezier7Path = UIBezierPath(style: self)
95 | bezier7Path.move(to: CGPoint(x: 45.67, y: 62.59))
96 | bezier7Path.addCurve(to: CGPoint(x: 41.86, y: 73.45), controlPoint1: CGPoint(x: 46.57, y: 65.52), controlPoint2: CGPoint(x: 44.88, y: 72.43))
97 |
98 | context.saveGState()
99 | context.setLineDash(phase: 0, lengths: [line2Dash, 300])
100 | bezier7Path.stroke()
101 | context.restoreGState()
102 |
103 | // Bezier 8 Drawing
104 | let bezier8Path = UIBezierPath(style: self)
105 | bezier8Path.move(to: CGPoint(x: 33.12, y: 53.48))
106 | bezier8Path.addCurve(to: CGPoint(x: 48.58, y: 37.83), controlPoint1: CGPoint(x: 33.12, y: 44.83), controlPoint2: CGPoint(x: 40.04, y: 37.83))
107 | bezier8Path.addCurve(to: CGPoint(x: 67.06, y: 51.63), controlPoint1: CGPoint(x: 61.38, y: 37.83), controlPoint2: CGPoint(x: 60.86, y: 49.84))
108 |
109 | context.saveGState()
110 | context.setLineDash(phase: 0, lengths: [line6Dash, 300])
111 | bezier8Path.stroke()
112 | context.restoreGState()
113 |
114 | // Bezier 9 Drawing
115 | let bezier9Path = UIBezierPath(style: self)
116 | bezier9Path.move(to: CGPoint(x: 33.12, y: 56.63))
117 | bezier9Path.addCurve(to: CGPoint(x: 34.06, y: 61.37), controlPoint1: CGPoint(x: 33.12, y: 58.75), controlPoint2: CGPoint(x: 34.06, y: 61.37))
118 |
119 | context.saveGState()
120 | context.setLineDash(phase: 0, lengths: [line11Dash, 300])
121 | bezier9Path.stroke()
122 | context.restoreGState()
123 |
124 | // Bezier 10 Drawing
125 | let bezier10Path = UIBezierPath(style: self)
126 | bezier10Path.move(to: CGPoint(x: 62.19, y: 39.28))
127 | bezier10Path.addCurve(to: CGPoint(x: 48.67, y: 33.37), controlPoint1: CGPoint(x: 61.19, y: 37.57), controlPoint2: CGPoint(x: 56.5, y: 33.37))
128 | bezier10Path.addCurve(to: CGPoint(x: 34.9, y: 39.28), controlPoint1: CGPoint(x: 40.85, y: 33.37), controlPoint2: CGPoint(x: 35.9, y: 37.57))
129 |
130 | context.saveGState()
131 | context.setLineDash(phase: 0, lengths: [line7Dash, 300])
132 | bezier10Path.stroke()
133 | context.restoreGState()
134 |
135 | // Bezier 11 Drawing
136 | let bezier11Path = UIBezierPath(style: self)
137 | bezier11Path.move(to: CGPoint(x: 39.13, y: 31.46))
138 | bezier11Path.addCurve(to: CGPoint(x: 48.57, y: 29.28), controlPoint1: CGPoint(x: 39.13, y: 31.46), controlPoint2: CGPoint(x: 42.77, y: 29.28))
139 | bezier11Path.addCurve(to: CGPoint(x: 57.96, y: 31.46), controlPoint1: CGPoint(x: 54.75, y: 29.28), controlPoint2: CGPoint(x: 57.96, y: 31.46))
140 |
141 | context.saveGState()
142 | context.setLineDash(phase: 0, lengths: [line8Dash, 300])
143 | bezier11Path.stroke()
144 | context.restoreGState()
145 |
146 | // Bezier 12 Drawing
147 | let bezier12Path = UIBezierPath(style: self)
148 | bezier12Path.move(to: CGPoint(x: 64.48, y: 42.8))
149 | bezier12Path.addCurve(to: CGPoint(x: 66.36, y: 46.58), controlPoint1: CGPoint(x: 64.48, y: 42.8), controlPoint2: CGPoint(x: 65.89, y: 45.05))
150 |
151 | context.saveGState()
152 | context.setLineDash(phase: 0, lengths: [line10Dash, 300])
153 | bezier12Path.stroke()
154 | context.restoreGState()
155 |
156 | // Bez 1 Drawing
157 | let bez1Path = UIBezierPath(style: self)
158 | bez1Path.move(to: CGPoint(x: 62.95, y: 64.14))
159 | bez1Path.addCurve(to: CGPoint(x: 52.68, y: 52.4), controlPoint1: CGPoint(x: 58.31, y: 60.43), controlPoint2: CGPoint(x: 54.11, y: 57.47))
160 | bez1Path.addCurve(to: CGPoint(x: 48.02, y: 49.72), controlPoint1: CGPoint(x: 52.1, y: 50.32), controlPoint2: CGPoint(x: 50.02, y: 49.12))
161 | bez1Path.addCurve(to: CGPoint(x: 45.44, y: 54.56), controlPoint1: CGPoint(x: 46.02, y: 50.32), controlPoint2: CGPoint(x: 44.87, y: 52.48))
162 | bez1Path.addCurve(to: CGPoint(x: 58.38, y: 70.34), controlPoint1: CGPoint(x: 47.06, y: 60.4), controlPoint2: CGPoint(x: 52.82, y: 65.77))
163 |
164 | context.saveGState()
165 | context.setLineDash(phase: 0, lengths: [line3Dash, 300])
166 | bez1Path.stroke()
167 | context.restoreGState()
168 |
169 | // Bezier 6 Drawing
170 | let bezier6Path = UIBezierPath(style: self)
171 | bezier6Path.move(to: CGPoint(x: 55.33, y: 73.45))
172 | bezier6Path.addCurve(to: CGPoint(x: 50, y: 68.79), controlPoint1: CGPoint(x: 54.37, y: 72.45), controlPoint2: CGPoint(x: 52.47, y: 68.79))
173 | bezier6Path.addCurve(to: CGPoint(x: 47.71, y: 75), controlPoint1: CGPoint(x: 47.53, y: 68.79), controlPoint2: CGPoint(x: 47.71, y: 75))
174 |
175 | context.saveGState()
176 | context.setLineDash(phase: 0, lengths: [line1Dash, 300])
177 | bezier6Path.stroke()
178 | context.restoreGState()
179 |
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/Example/Showcase.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | E70E4BE823916C4E00E0E4D6 /* MKJIcons in Frameworks */ = {isa = PBXBuildFile; productRef = E70E4BE723916C4E00E0E4D6 /* MKJIcons */; };
11 | E70E4BEA2391701600E0E4D6 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E70E4BE92391701600E0E4D6 /* TabBarController.swift */; };
12 | E714E8461CCA285C00E18E52 /* AnimatedIcon+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = E714E8451CCA285C00E18E52 /* AnimatedIcon+Style.swift */; };
13 | E796FD1C1CC6AA8A003DC351 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E796FD1B1CC6AA8A003DC351 /* TabBar.swift */; };
14 | E796FD1E1CC6AEAE003DC351 /* Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = E796FD1D1CC6AEAE003DC351 /* Style.swift */; };
15 | E7BE8DF51CC57FF2007DADED /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7BE8DF41CC57FF2007DADED /* AppDelegate.swift */; };
16 | E7BE8DF71CC57FF2007DADED /* ShowcaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7BE8DF61CC57FF2007DADED /* ShowcaseViewController.swift */; };
17 | E7BE8DF91CC57FF2007DADED /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7BE8DF81CC57FF2007DADED /* SettingsViewController.swift */; };
18 | E7BE8DFC1CC57FF2007DADED /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7BE8DFA1CC57FF2007DADED /* Main.storyboard */; };
19 | E7BE8DFE1CC57FF2007DADED /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E7BE8DFD1CC57FF2007DADED /* Assets.xcassets */; };
20 | E7BE8E011CC57FF2007DADED /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7BE8DFF1CC57FF2007DADED /* LaunchScreen.storyboard */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXCopyFilesBuildPhase section */
24 | E7BE8E231CC582FF007DADED /* Embed Frameworks */ = {
25 | isa = PBXCopyFilesBuildPhase;
26 | buildActionMask = 2147483647;
27 | dstPath = "";
28 | dstSubfolderSpec = 10;
29 | files = (
30 | );
31 | name = "Embed Frameworks";
32 | runOnlyForDeploymentPostprocessing = 0;
33 | };
34 | /* End PBXCopyFilesBuildPhase section */
35 |
36 | /* Begin PBXFileReference section */
37 | E70E4BE423916C2D00E0E4D6 /* MKJIcons */ = {isa = PBXFileReference; lastKnownFileType = folder; name = MKJIcons; path = ..; sourceTree = ""; };
38 | E70E4BE92391701600E0E4D6 /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; };
39 | E714E8451CCA285C00E18E52 /* AnimatedIcon+Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AnimatedIcon+Style.swift"; sourceTree = ""; };
40 | E796FD1B1CC6AA8A003DC351 /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = TabBar.swift; sourceTree = ""; };
41 | E796FD1D1CC6AEAE003DC351 /* Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Style.swift; sourceTree = ""; };
42 | E7BE8DF11CC57FF2007DADED /* Showcase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Showcase.app; sourceTree = BUILT_PRODUCTS_DIR; };
43 | E7BE8DF41CC57FF2007DADED /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; };
44 | E7BE8DF61CC57FF2007DADED /* ShowcaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ShowcaseViewController.swift; sourceTree = ""; };
45 | E7BE8DF81CC57FF2007DADED /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SettingsViewController.swift; sourceTree = ""; };
46 | E7BE8DFB1CC57FF2007DADED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
47 | E7BE8DFD1CC57FF2007DADED /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Showcase/Assets.xcassets; sourceTree = ""; };
48 | E7BE8E001CC57FF2007DADED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
49 | E7BE8E021CC57FF2007DADED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Showcase/Info.plist; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | E7BE8DEE1CC57FF2007DADED /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | E70E4BE823916C4E00E0E4D6 /* MKJIcons in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | E70E4BE323916C1700E0E4D6 /* Frameworks */ = {
65 | isa = PBXGroup;
66 | children = (
67 | E70E4BE423916C2D00E0E4D6 /* MKJIcons */,
68 | );
69 | name = Frameworks;
70 | sourceTree = "";
71 | };
72 | E7BE8DE81CC57FF2007DADED = {
73 | isa = PBXGroup;
74 | children = (
75 | E7BE8DF31CC57FF2007DADED /* Sources */,
76 | E70E4BE323916C1700E0E4D6 /* Frameworks */,
77 | E7BE8E161CC580F7007DADED /* Interface */,
78 | E7BE8E141CC5809A007DADED /* Resources */,
79 | E7BE8DF21CC57FF2007DADED /* Products */,
80 | );
81 | sourceTree = "";
82 | };
83 | E7BE8DF21CC57FF2007DADED /* Products */ = {
84 | isa = PBXGroup;
85 | children = (
86 | E7BE8DF11CC57FF2007DADED /* Showcase.app */,
87 | );
88 | name = Products;
89 | sourceTree = "";
90 | };
91 | E7BE8DF31CC57FF2007DADED /* Sources */ = {
92 | isa = PBXGroup;
93 | children = (
94 | E796FD1D1CC6AEAE003DC351 /* Style.swift */,
95 | E714E8451CCA285C00E18E52 /* AnimatedIcon+Style.swift */,
96 | E7BE8DF41CC57FF2007DADED /* AppDelegate.swift */,
97 | E7BE8DF61CC57FF2007DADED /* ShowcaseViewController.swift */,
98 | E7BE8DF81CC57FF2007DADED /* SettingsViewController.swift */,
99 | E796FD1B1CC6AA8A003DC351 /* TabBar.swift */,
100 | E70E4BE92391701600E0E4D6 /* TabBarController.swift */,
101 | );
102 | name = Sources;
103 | path = Showcase;
104 | sourceTree = "";
105 | };
106 | E7BE8E141CC5809A007DADED /* Resources */ = {
107 | isa = PBXGroup;
108 | children = (
109 | E7BE8DFD1CC57FF2007DADED /* Assets.xcassets */,
110 | E7BE8E021CC57FF2007DADED /* Info.plist */,
111 | );
112 | name = Resources;
113 | sourceTree = "";
114 | };
115 | E7BE8E161CC580F7007DADED /* Interface */ = {
116 | isa = PBXGroup;
117 | children = (
118 | E7BE8DFA1CC57FF2007DADED /* Main.storyboard */,
119 | E7BE8DFF1CC57FF2007DADED /* LaunchScreen.storyboard */,
120 | );
121 | name = Interface;
122 | sourceTree = "";
123 | };
124 | /* End PBXGroup section */
125 |
126 | /* Begin PBXNativeTarget section */
127 | E7BE8DF01CC57FF2007DADED /* Showcase */ = {
128 | isa = PBXNativeTarget;
129 | buildConfigurationList = E7BE8E051CC57FF2007DADED /* Build configuration list for PBXNativeTarget "Showcase" */;
130 | buildPhases = (
131 | E7BE8DED1CC57FF2007DADED /* Sources */,
132 | E7BE8DEE1CC57FF2007DADED /* Frameworks */,
133 | E7BE8DEF1CC57FF2007DADED /* Resources */,
134 | E7BE8E231CC582FF007DADED /* Embed Frameworks */,
135 | );
136 | buildRules = (
137 | );
138 | dependencies = (
139 | E70E4BE623916C4900E0E4D6 /* PBXTargetDependency */,
140 | );
141 | name = Showcase;
142 | packageProductDependencies = (
143 | E70E4BE723916C4E00E0E4D6 /* MKJIcons */,
144 | );
145 | productName = Showcase;
146 | productReference = E7BE8DF11CC57FF2007DADED /* Showcase.app */;
147 | productType = "com.apple.product-type.application";
148 | };
149 | /* End PBXNativeTarget section */
150 |
151 | /* Begin PBXProject section */
152 | E7BE8DE91CC57FF2007DADED /* Project object */ = {
153 | isa = PBXProject;
154 | attributes = {
155 | LastSwiftUpdateCheck = 0730;
156 | LastUpgradeCheck = 1120;
157 | ORGANIZATIONNAME = "Matěj Kašpar Jirásek";
158 | TargetAttributes = {
159 | E7BE8DF01CC57FF2007DADED = {
160 | CreatedOnToolsVersion = 7.3;
161 | DevelopmentTeam = QLPB86L68N;
162 | LastSwiftMigration = 1120;
163 | };
164 | };
165 | };
166 | buildConfigurationList = E7BE8DEC1CC57FF2007DADED /* Build configuration list for PBXProject "Showcase" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = en;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = E7BE8DE81CC57FF2007DADED;
175 | productRefGroup = E7BE8DF21CC57FF2007DADED /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | E7BE8DF01CC57FF2007DADED /* Showcase */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | E7BE8DEF1CC57FF2007DADED /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | E7BE8E011CC57FF2007DADED /* LaunchScreen.storyboard in Resources */,
190 | E7BE8DFE1CC57FF2007DADED /* Assets.xcassets in Resources */,
191 | E7BE8DFC1CC57FF2007DADED /* Main.storyboard in Resources */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | /* End PBXResourcesBuildPhase section */
196 |
197 | /* Begin PBXSourcesBuildPhase section */
198 | E7BE8DED1CC57FF2007DADED /* Sources */ = {
199 | isa = PBXSourcesBuildPhase;
200 | buildActionMask = 2147483647;
201 | files = (
202 | E714E8461CCA285C00E18E52 /* AnimatedIcon+Style.swift in Sources */,
203 | E7BE8DF91CC57FF2007DADED /* SettingsViewController.swift in Sources */,
204 | E796FD1E1CC6AEAE003DC351 /* Style.swift in Sources */,
205 | E7BE8DF51CC57FF2007DADED /* AppDelegate.swift in Sources */,
206 | E70E4BEA2391701600E0E4D6 /* TabBarController.swift in Sources */,
207 | E796FD1C1CC6AA8A003DC351 /* TabBar.swift in Sources */,
208 | E7BE8DF71CC57FF2007DADED /* ShowcaseViewController.swift in Sources */,
209 | );
210 | runOnlyForDeploymentPostprocessing = 0;
211 | };
212 | /* End PBXSourcesBuildPhase section */
213 |
214 | /* Begin PBXTargetDependency section */
215 | E70E4BE623916C4900E0E4D6 /* PBXTargetDependency */ = {
216 | isa = PBXTargetDependency;
217 | productRef = E70E4BE523916C4900E0E4D6 /* MKJIcons */;
218 | };
219 | /* End PBXTargetDependency section */
220 |
221 | /* Begin PBXVariantGroup section */
222 | E7BE8DFA1CC57FF2007DADED /* Main.storyboard */ = {
223 | isa = PBXVariantGroup;
224 | children = (
225 | E7BE8DFB1CC57FF2007DADED /* Base */,
226 | );
227 | name = Main.storyboard;
228 | path = Showcase;
229 | sourceTree = "";
230 | };
231 | E7BE8DFF1CC57FF2007DADED /* LaunchScreen.storyboard */ = {
232 | isa = PBXVariantGroup;
233 | children = (
234 | E7BE8E001CC57FF2007DADED /* Base */,
235 | );
236 | name = LaunchScreen.storyboard;
237 | path = Showcase;
238 | sourceTree = "";
239 | };
240 | /* End PBXVariantGroup section */
241 |
242 | /* Begin XCBuildConfiguration section */
243 | E7BE8E031CC57FF2007DADED /* Debug */ = {
244 | isa = XCBuildConfiguration;
245 | buildSettings = {
246 | ALWAYS_SEARCH_USER_PATHS = NO;
247 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
248 | CLANG_ANALYZER_NONNULL = YES;
249 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
250 | CLANG_CXX_LIBRARY = "libc++";
251 | CLANG_ENABLE_MODULES = YES;
252 | CLANG_ENABLE_OBJC_ARC = YES;
253 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
254 | CLANG_WARN_BOOL_CONVERSION = YES;
255 | CLANG_WARN_COMMA = YES;
256 | CLANG_WARN_CONSTANT_CONVERSION = YES;
257 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
259 | CLANG_WARN_EMPTY_BODY = YES;
260 | CLANG_WARN_ENUM_CONVERSION = YES;
261 | CLANG_WARN_INFINITE_RECURSION = YES;
262 | CLANG_WARN_INT_CONVERSION = YES;
263 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
264 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
265 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
266 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
267 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
268 | CLANG_WARN_STRICT_PROTOTYPES = YES;
269 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
270 | CLANG_WARN_UNREACHABLE_CODE = YES;
271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
273 | COPY_PHASE_STRIP = NO;
274 | DEBUG_INFORMATION_FORMAT = dwarf;
275 | ENABLE_STRICT_OBJC_MSGSEND = YES;
276 | ENABLE_TESTABILITY = YES;
277 | GCC_C_LANGUAGE_STANDARD = gnu99;
278 | GCC_DYNAMIC_NO_PIC = NO;
279 | GCC_NO_COMMON_BLOCKS = YES;
280 | GCC_OPTIMIZATION_LEVEL = 0;
281 | GCC_PREPROCESSOR_DEFINITIONS = (
282 | "DEBUG=1",
283 | "$(inherited)",
284 | );
285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
287 | GCC_WARN_UNDECLARED_SELECTOR = YES;
288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
289 | GCC_WARN_UNUSED_FUNCTION = YES;
290 | GCC_WARN_UNUSED_VARIABLE = YES;
291 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
292 | MTL_ENABLE_DEBUG_INFO = YES;
293 | ONLY_ACTIVE_ARCH = YES;
294 | SDKROOT = iphoneos;
295 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
296 | TARGETED_DEVICE_FAMILY = "1,2";
297 | };
298 | name = Debug;
299 | };
300 | E7BE8E041CC57FF2007DADED /* Release */ = {
301 | isa = XCBuildConfiguration;
302 | buildSettings = {
303 | ALWAYS_SEARCH_USER_PATHS = NO;
304 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
305 | CLANG_ANALYZER_NONNULL = YES;
306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
307 | CLANG_CXX_LIBRARY = "libc++";
308 | CLANG_ENABLE_MODULES = YES;
309 | CLANG_ENABLE_OBJC_ARC = YES;
310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
311 | CLANG_WARN_BOOL_CONVERSION = YES;
312 | CLANG_WARN_COMMA = YES;
313 | CLANG_WARN_CONSTANT_CONVERSION = YES;
314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
316 | CLANG_WARN_EMPTY_BODY = YES;
317 | CLANG_WARN_ENUM_CONVERSION = YES;
318 | CLANG_WARN_INFINITE_RECURSION = YES;
319 | CLANG_WARN_INT_CONVERSION = YES;
320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
325 | CLANG_WARN_STRICT_PROTOTYPES = YES;
326 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
327 | CLANG_WARN_UNREACHABLE_CODE = YES;
328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
330 | COPY_PHASE_STRIP = NO;
331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
332 | ENABLE_NS_ASSERTIONS = NO;
333 | ENABLE_STRICT_OBJC_MSGSEND = YES;
334 | GCC_C_LANGUAGE_STANDARD = gnu99;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
338 | GCC_WARN_UNDECLARED_SELECTOR = YES;
339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
340 | GCC_WARN_UNUSED_FUNCTION = YES;
341 | GCC_WARN_UNUSED_VARIABLE = YES;
342 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
343 | MTL_ENABLE_DEBUG_INFO = NO;
344 | SDKROOT = iphoneos;
345 | SWIFT_COMPILATION_MODE = wholemodule;
346 | SWIFT_OPTIMIZATION_LEVEL = "-O";
347 | TARGETED_DEVICE_FAMILY = "1,2";
348 | VALIDATE_PRODUCT = YES;
349 | };
350 | name = Release;
351 | };
352 | E7BE8E061CC57FF2007DADED /* Debug */ = {
353 | isa = XCBuildConfiguration;
354 | buildSettings = {
355 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356 | DEVELOPMENT_TEAM = QLPB86L68N;
357 | INFOPLIST_FILE = Showcase/Info.plist;
358 | LD_RUNPATH_SEARCH_PATHS = (
359 | "$(inherited)",
360 | "@executable_path/Frameworks",
361 | );
362 | PRODUCT_BUNDLE_IDENTIFIER = is.mkj.icons.example;
363 | PRODUCT_NAME = "$(TARGET_NAME)";
364 | SWIFT_VERSION = 5.0;
365 | };
366 | name = Debug;
367 | };
368 | E7BE8E071CC57FF2007DADED /* Release */ = {
369 | isa = XCBuildConfiguration;
370 | buildSettings = {
371 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
372 | DEVELOPMENT_TEAM = QLPB86L68N;
373 | INFOPLIST_FILE = Showcase/Info.plist;
374 | LD_RUNPATH_SEARCH_PATHS = (
375 | "$(inherited)",
376 | "@executable_path/Frameworks",
377 | );
378 | PRODUCT_BUNDLE_IDENTIFIER = is.mkj.icons.example;
379 | PRODUCT_NAME = "$(TARGET_NAME)";
380 | SWIFT_VERSION = 5.0;
381 | };
382 | name = Release;
383 | };
384 | /* End XCBuildConfiguration section */
385 |
386 | /* Begin XCConfigurationList section */
387 | E7BE8DEC1CC57FF2007DADED /* Build configuration list for PBXProject "Showcase" */ = {
388 | isa = XCConfigurationList;
389 | buildConfigurations = (
390 | E7BE8E031CC57FF2007DADED /* Debug */,
391 | E7BE8E041CC57FF2007DADED /* Release */,
392 | );
393 | defaultConfigurationIsVisible = 0;
394 | defaultConfigurationName = Release;
395 | };
396 | E7BE8E051CC57FF2007DADED /* Build configuration list for PBXNativeTarget "Showcase" */ = {
397 | isa = XCConfigurationList;
398 | buildConfigurations = (
399 | E7BE8E061CC57FF2007DADED /* Debug */,
400 | E7BE8E071CC57FF2007DADED /* Release */,
401 | );
402 | defaultConfigurationIsVisible = 0;
403 | defaultConfigurationName = Release;
404 | };
405 | /* End XCConfigurationList section */
406 |
407 | /* Begin XCSwiftPackageProductDependency section */
408 | E70E4BE523916C4900E0E4D6 /* MKJIcons */ = {
409 | isa = XCSwiftPackageProductDependency;
410 | productName = MKJIcons;
411 | };
412 | E70E4BE723916C4E00E0E4D6 /* MKJIcons */ = {
413 | isa = XCSwiftPackageProductDependency;
414 | productName = MKJIcons;
415 | };
416 | /* End XCSwiftPackageProductDependency section */
417 | };
418 | rootObject = E7BE8DE91CC57FF2007DADED /* Project object */;
419 | }
420 |
--------------------------------------------------------------------------------
/Example/Showcase/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
616 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
--------------------------------------------------------------------------------