├── .github
└── FUNDING.yml
├── .gitignore
├── .swiftlint.yml
├── .travis.yml
├── LICENSE
├── LTMorphingLabel.podspec
├── LTMorphingLabel
├── Info.plist
├── LTCharacterDiffResult.swift
├── LTCharacterLimbo.swift
├── LTEasing.swift
├── LTEmitterView.swift
├── LTMorphingEffect.swift
├── LTMorphingLabel+Anvil.swift
├── LTMorphingLabel+Burn.swift
├── LTMorphingLabel+Evaporate.swift
├── LTMorphingLabel+Fall.swift
├── LTMorphingLabel+Pixelate.swift
├── LTMorphingLabel+Sparkle.swift
├── LTMorphingLabel.h
├── LTMorphingLabel.swift
├── LTStringDiffResult.swift
├── Particles
│ ├── Fire.png
│ ├── Fragment.png
│ ├── Smoke.png
│ └── Sparkle.png
├── SwiftUI
│ └── MorphingText.swift
└── tvOS-Info.plist
├── LTMorphingLabelDemo.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── LTMorphingLabelDemo.xccheckout
│ └── xcuserdata
│ │ └── lex.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcshareddata
│ └── xcschemes
│ │ ├── LTMorphingLabelDemo.xcscheme
│ │ └── MorphingLabel.xcscheme
└── xcuserdata
│ └── lex.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── LTMorphingLabelDemo
├── AppDelegate.swift
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-76.png
│ │ ├── Icon-76@2x.png
│ │ └── Icon-83.5@2x.png
│ └── Contents.json
├── Info.plist
├── LTDemoViewController.swift
├── LTMorphingLabelDemo.storyboard
└── Launch Screen.storyboard
├── LTMorphingLabelTests
├── Info.plist
└── LTMorphingLabelTests.swift
├── LTMorphingLabelUITests
├── Info.plist
└── LTMorphingLabelUITests.swift
├── Package.swift
├── README.md
├── Sources
└── MorphingLabel
└── build_xcframework.sh
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: ltmorphinglabel
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/osx,carthage,swift
3 |
4 | ### Carthage ###
5 | # Carthage
6 | #
7 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
8 | # Carthage/Checkouts
9 |
10 | Carthage/Build
11 |
12 | ### OSX ###
13 | *.DS_Store
14 | .AppleDouble
15 | .LSOverride
16 |
17 | # Icon must end with two \r
18 | Icon
19 |
20 | # Thumbnails
21 | ._*
22 |
23 | # Files that might appear in the root of a volume
24 | .DocumentRevisions-V100
25 | .fseventsd
26 | .Spotlight-V100
27 | .TemporaryItems
28 | .Trashes
29 | .VolumeIcon.icns
30 | .com.apple.timemachine.donotpresent
31 |
32 | # Directories potentially created on remote AFP share
33 | .AppleDB
34 | .AppleDesktop
35 | Network Trash Folder
36 | Temporary Items
37 | .apdisk
38 |
39 | ### Swift ###
40 | # Xcode
41 | #
42 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
43 |
44 | ## Build generated
45 | build/
46 | DerivedData/
47 |
48 | ## Various settings
49 | *.pbxuser
50 | !default.pbxuser
51 | *.mode1v3
52 | !default.mode1v3
53 | *.mode2v3
54 | !default.mode2v3
55 | *.perspectivev3
56 | !default.perspectivev3
57 | xcuserdata/
58 |
59 | ## Other
60 | *.moved-aside
61 | *.xccheckout
62 | *.xcscmblueprint
63 |
64 | ## Obj-C/Swift specific
65 | *.hmap
66 | *.ipa
67 | *.dSYM.zip
68 | *.dSYM
69 |
70 | ## Playgrounds
71 | timeline.xctimeline
72 | playground.xcworkspace
73 |
74 | # Swift Package Manager
75 | #
76 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
77 | # Packages/
78 | # Package.pins
79 | .build/
80 |
81 | # CocoaPods - Refactored to standalone file
82 |
83 | # Carthage - Refactored to standalone file
84 |
85 | # fastlane
86 | #
87 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
88 | # screenshots whenever they are needed.
89 | # For more information about the recommended setup visit:
90 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
91 |
92 | fastlane/report.xml
93 | fastlane/Preview.html
94 | fastlane/screenshots
95 | fastlane/test_output
96 |
97 | # End of https://www.gitignore.io/api/osx,carthage,swift
98 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - todo
3 | - force_cast
4 | - trailing_whitespace
5 | - colon
6 | - identifier_name
7 | - type_name
8 | - comma
9 | - closure_parameter_position
10 | excluded:
11 | - Carthage
12 | - Pods
13 | line_length: 120
14 | function_body_length:
15 | - 230
16 | - 300
17 | type_body_length:
18 | - 300
19 | - 600
20 | file_length:
21 | - 600
22 | - 800
23 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode12
2 | language: objective-c
3 | script:
4 | - |
5 | xcodebuild test \
6 | -project LTMorphingLabelDemo.xcodeproj \
7 | -scheme LTMorphingLabelDemo \
8 | -sdk iphonesimulator \
9 | -destination 'platform=iOS Simulator,name=iPhone X,OS=latest' \
10 | | xcpretty
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright © 2020 Lex Tang, https://lexrus.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the “Software”), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/LTMorphingLabel.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "LTMorphingLabel"
4 | s.version = "0.9.3"
5 | s.summary = "Graceful morphing effects for UILabel written in Swift."
6 | s.description = <<-DESC
7 | A morphing UILabel subclass written in Swift.
8 | The .Scale effect mimicked Apple's QuickType animation of iOS
9 | 8 in WWDC 2014. New morphing effects are available as
10 | Swift extensions.
11 | DESC
12 | s.homepage = "https://github.com/lexrus/LTMorphingLabel"
13 | s.screenshots = "https://cloud.githubusercontent.com/assets/219689/3491822/96bf5de6-059d-11e4-9826-a6f82025d1af.gif",
14 | "https://cloud.githubusercontent.com/assets/219689/3491838/ffc5aff2-059d-11e4-970c-6e2d7664785a.gif",
15 | "https://cloud.githubusercontent.com/assets/219689/3491840/173c2238-059e-11e4-9b33-dcd21edae9e2.gif",
16 | "https://cloud.githubusercontent.com/assets/219689/3491845/29bb0f8c-059e-11e4-9ef8-de56bec1baba.gif",
17 | "https://cloud.githubusercontent.com/assets/219689/3508789/31e9fafe-0690-11e4-9a76-ba3ef45eb53a.gif",
18 | "https://cloud.githubusercontent.com/assets/219689/3594949/815cd3e8-0caa-11e4-9738-278a9c959478.gif"
19 | s.license = { :type => "MIT", :file => "LICENSE" }
20 | s.author = { "Lex Tang" => "lexrus@gmail.com" }
21 | s.social_media_url = "https://twitter.com/lexrus"
22 | s.ios.deployment_target = "9.0"
23 | s.tvos.deployment_target = "9.0"
24 | s.swift_versions = ['5.3']
25 | s.source = {
26 | :git => "https://github.com/lexrus/LTMorphingLabel.git",
27 | :tag => s.version
28 | }
29 | s.source_files = "LTMorphingLabel/*.{h,swift}", "LTMorphingLabel/**/*.{swift}"
30 | s.resources = "LTMorphingLabel/Particles/*.png"
31 | s.frameworks = "UIKit", "Foundation", "QuartzCore"
32 | s.requires_arc = true
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/LTMorphingLabel/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTCharacterDiffResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTCharacterDiffResult.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import Foundation
29 |
30 | public enum LTCharacterDiffResult: CustomDebugStringConvertible, Equatable {
31 |
32 | case same
33 | case add
34 | case delete
35 | case move(offset: Int)
36 | case moveAndAdd(offset: Int)
37 | case replace
38 |
39 | public var debugDescription: String {
40 | switch self {
41 | case .same:
42 | return "The character is unchanged."
43 | case .add:
44 | return "A new character is ADDED."
45 | case .delete:
46 | return "The character is DELETED."
47 | case .move(let offset):
48 | return "The character is MOVED to \(offset)."
49 | case .moveAndAdd(let offset):
50 | return "The character is MOVED to \(offset) and a new character is ADDED."
51 | case .replace:
52 | return "The character is REPLACED with a new character."
53 | }
54 | }
55 |
56 | }
57 |
58 | public func == (lhs: LTCharacterDiffResult, rhs: LTCharacterDiffResult) -> Bool {
59 | switch (lhs, rhs) {
60 | case (.move(let offset0), .move(let offset1)):
61 | return offset0 == offset1
62 |
63 | case (.moveAndAdd(let offset0), .moveAndAdd(let offset1)):
64 | return offset0 == offset1
65 |
66 | case (.add, .add):
67 | return true
68 |
69 | case (.delete, .delete):
70 | return true
71 |
72 | case (.replace, .replace):
73 | return true
74 |
75 | case (.same, .same):
76 | return true
77 |
78 | default: return false
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTCharacterLimbo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTCharacterLimbo.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | public struct LTCharacterLimbo: CustomDebugStringConvertible {
31 |
32 | public let char: Character
33 | public var rect: CGRect
34 | public var alpha: CGFloat
35 | public var size: CGFloat
36 | public var drawingProgress: CGFloat = 0.0
37 |
38 | public var debugDescription: String {
39 | return "Character: '\(char)'"
40 | + "drawIn (\(rect.origin.x), \(rect.origin.y), "
41 | + "\(rect.size.width)x\(rect.size.height) "
42 | + "with alpha \(alpha) "
43 | + "and \(size)pt font."
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTEasing.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTEasing.swift
3 | // LTMorphingLabelDemo
4 | //
5 | // Created by Lex on 7/1/14.
6 | // Copyright (c) 2015 lexrus.com. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js
12 | // t = currentTime
13 | // b = beginning
14 | // c = change
15 | // d = duration
16 |
17 | public struct LTEasing {
18 |
19 | public static func easeOutQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
20 | return { (f: Float) in
21 | return c * (pow(f, 5) + 1.0) + b
22 | }(t / d - 1.0)
23 | }
24 |
25 | public static func easeInQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
26 | return { (f: Float) in
27 | c * pow(f, 5) + b
28 | }(t / d)
29 | }
30 |
31 | public static func easeOutBack(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
32 | let s: Float = 2.70158
33 | let t2: Float = t / d - 1.0
34 | return Float(c * (t2 * t2 * ((s + 1.0) * t2 + s) + 1.0)) + b
35 | }
36 |
37 | public static func easeOutBounce(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
38 | return { (f: Float) in
39 | if f < 1 / 2.75 {
40 | return c * 7.5625 * f * f + b
41 | } else if f < 2 / 2.75 {
42 | let t = f - 1.5 / 2.75
43 | return c * (7.5625 * t * t + 0.75) + b
44 | } else if f < 2.5 / 2.75 {
45 | let t = f - 2.25 / 2.75
46 | return c * (7.5625 * t * t + 0.9375) + b
47 | } else {
48 | let t = f - 2.625 / 2.75
49 | return c * (7.5625 * t * t + 0.984375) + b
50 | }
51 | }(t / d)
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTEmitterView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTEmitterView.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | private func < (lhs: T?, rhs: T?) -> Bool {
31 | switch (lhs, rhs) {
32 | case let (l?, r?):
33 | return l < r
34 | case (nil, _?):
35 | return true
36 | default:
37 | return false
38 | }
39 | }
40 |
41 | private func > (lhs: T?, rhs: T?) -> Bool {
42 | switch (lhs, rhs) {
43 | case let (l?, r?):
44 | return l > r
45 | default:
46 | return rhs < lhs
47 | }
48 | }
49 |
50 | public struct LTEmitter {
51 |
52 | let layer: CAEmitterLayer = {
53 | let layer = CAEmitterLayer()
54 | layer.emitterPosition = CGPoint(x: 10, y: 10)
55 | layer.emitterSize = CGSize(width: 10, height: 1)
56 | layer.renderMode = .unordered
57 | layer.emitterShape = .line
58 | return layer
59 | }()
60 |
61 | let cell: CAEmitterCell = {
62 | let cell = CAEmitterCell()
63 | cell.name = "sparkle"
64 | cell.birthRate = 150.0
65 | cell.velocity = 50.0
66 | cell.velocityRange = -80.0
67 | cell.lifetime = 0.16
68 | cell.lifetimeRange = 0.1
69 | cell.emissionLongitude = CGFloat(Double.pi / 2 * 2.0)
70 | cell.emissionRange = CGFloat(Double.pi / 2 * 2.0)
71 | cell.scale = 0.1
72 | cell.yAcceleration = 100
73 | cell.scaleSpeed = -0.06
74 | cell.scaleRange = 0.1
75 | return cell
76 | }()
77 |
78 | public var duration: Float = 0.6
79 |
80 | init(name: String, particleName: String, duration: Float) {
81 | cell.name = name
82 | self.duration = duration
83 | var image: UIImage?
84 | defer {
85 | cell.contents = image?.cgImage
86 | }
87 |
88 | image = UIImage(named: particleName)
89 |
90 | if image != nil {
91 | return
92 | }
93 | // Load from Framework
94 | image = UIImage(
95 | named: particleName,
96 | in: Bundle(for: LTMorphingLabel.self),
97 | compatibleWith: nil)
98 | }
99 |
100 | public func play() {
101 | if layer.emitterCells?.count > 0 {
102 | return
103 | }
104 |
105 | layer.emitterCells = [cell]
106 | let d = DispatchTime.now() + Double(Int64(duration * Float(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
107 | DispatchQueue.main.asyncAfter(deadline: d) { [weak layer] in
108 | layer?.birthRate = 0.0
109 | }
110 | }
111 |
112 | public func stop() {
113 | if nil != layer.superlayer {
114 | layer.emitterCells = nil
115 | layer.removeFromSuperlayer()
116 | }
117 | }
118 |
119 | func update(_ configureClosure: LTEmitterConfigureClosure? = .none) -> LTEmitter {
120 | configureClosure?(layer, cell)
121 | return self
122 | }
123 |
124 | }
125 |
126 | public typealias LTEmitterConfigureClosure = (CAEmitterLayer, CAEmitterCell) -> Void
127 |
128 | open class LTEmitterView: UIView {
129 |
130 | open lazy var emitters: [String: LTEmitter] = {
131 | var _emitters = [String: LTEmitter]()
132 | return _emitters
133 | }()
134 |
135 | open func createEmitter(
136 | _ name: String,
137 | particleName: String,
138 | duration: Float,
139 | configureClosure: LTEmitterConfigureClosure?
140 | ) -> LTEmitter {
141 |
142 | var emitter: LTEmitter
143 | if let e = emitters[name] {
144 | emitter = e
145 | } else {
146 | emitter = LTEmitter(
147 | name: name,
148 | particleName: particleName,
149 | duration: duration
150 | )
151 |
152 | configureClosure?(emitter.layer, emitter.cell)
153 |
154 | layer.addSublayer(emitter.layer)
155 | emitters.updateValue(emitter, forKey: name)
156 | }
157 | return emitter
158 | }
159 |
160 | open func removeAllEmitters() {
161 | emitters.forEach {
162 | $0.value.layer.removeFromSuperlayer()
163 | }
164 | emitters.removeAll(keepingCapacity: false)
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingEffect.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingEffect.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | @objc public enum LTMorphingEffect
31 | : Int
32 | , CustomStringConvertible
33 | , ExpressibleByIntegerLiteral
34 | , ExpressibleByStringLiteral
35 | , CaseIterable {
36 |
37 | public typealias IntegerLiteralType = Int
38 | public typealias StringLiteralType = String
39 |
40 | case scale = 0
41 | case evaporate
42 | case fall
43 | case pixelate
44 | case sparkle
45 | case burn
46 | case anvil
47 |
48 | public static let allValues = [
49 | "Scale", "Evaporate", "Fall", "Pixelate", "Sparkle", "Burn", "Anvil"
50 | ]
51 |
52 | public var description: String {
53 | switch self {
54 | case .evaporate:
55 | return "Evaporate"
56 | case .fall:
57 | return "Fall"
58 | case .pixelate:
59 | return "Pixelate"
60 | case .sparkle:
61 | return "Sparkle"
62 | case .burn:
63 | return "Burn"
64 | case .anvil:
65 | return "Anvil"
66 | default:
67 | return "Scale"
68 | }
69 | }
70 |
71 | public init(integerLiteral value: Int) {
72 | self = LTMorphingEffect(rawValue: value) ?? .scale
73 | }
74 |
75 | public init(stringLiteral value: String) {
76 | self = {
77 | switch value {
78 | case "Evaporate": return .evaporate
79 | case "Fall": return .fall
80 | case "Pixelate": return .pixelate
81 | case "Sparkle": return .sparkle
82 | case "Burn": return .burn
83 | case "Anvil": return .anvil
84 | default: return .scale
85 | }
86 | }()
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Anvil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Anvil.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | @objc
33 | func AnvilLoad() {
34 |
35 | startClosures["Anvil\(LTMorphingPhases.start)"] = {
36 | self.emitterView.removeAllEmitters()
37 |
38 | guard self.newRects.count > 0 else { return }
39 |
40 | let centerRect = self.newRects[Int(self.newRects.count / 2)]
41 |
42 | _ = self.emitterView.createEmitter(
43 | "leftSmoke",
44 | particleName: "Smoke",
45 | duration: 0.6
46 | ) { (layer, cell) in
47 | layer.emitterSize = CGSize(width: 1, height: 1)
48 | layer.emitterPosition = CGPoint(
49 | x: centerRect.origin.x,
50 | y: centerRect.origin.y + centerRect.size.height / 1.3)
51 | layer.renderMode = .unordered
52 | cell.emissionLongitude = CGFloat(Double.pi / 2)
53 | cell.scale = self.font.pointSize / 90.0
54 | cell.scaleSpeed = self.font.pointSize / 130
55 | cell.birthRate = 60
56 | cell.velocity = CGFloat(80 + Int(arc4random_uniform(60)))
57 | cell.velocityRange = 100
58 | cell.yAcceleration = -40
59 | cell.xAcceleration = 70
60 | cell.emissionLongitude = CGFloat(-Double.pi / 2)
61 | cell.emissionRange = CGFloat(Double.pi / 4) / 5.0
62 | cell.lifetime = self.morphingDuration * 2.0
63 | cell.spin = 10
64 | cell.alphaSpeed = -0.5 / self.morphingDuration
65 | }
66 |
67 | _ = self.emitterView.createEmitter(
68 | "rightSmoke",
69 | particleName: "Smoke",
70 | duration: 0.6
71 | ) { (layer, cell) in
72 | layer.emitterSize = CGSize(width: 1, height: 1)
73 | layer.emitterPosition = CGPoint(
74 | x: centerRect.origin.x,
75 | y: centerRect.origin.y + centerRect.size.height / 1.3)
76 | layer.renderMode = .unordered
77 | cell.emissionLongitude = CGFloat(Double.pi / 2)
78 | cell.scale = self.font.pointSize / 90.0
79 | cell.scaleSpeed = self.font.pointSize / 130
80 | cell.birthRate = 60
81 | cell.velocity = CGFloat(80 + Int(arc4random_uniform(60)))
82 | cell.velocityRange = 100
83 | cell.yAcceleration = -40
84 | cell.xAcceleration = -70
85 | cell.emissionLongitude = CGFloat(Double.pi / 2)
86 | cell.emissionRange = CGFloat(-Double.pi / 4) / 5.0
87 | cell.lifetime = self.morphingDuration * 2.0
88 | cell.spin = -10
89 | cell.alphaSpeed = -0.5 / self.morphingDuration
90 | }
91 |
92 | _ = self.emitterView.createEmitter(
93 | "leftFragments",
94 | particleName: "Fragment",
95 | duration: 0.6
96 | ) { (layer, cell) in
97 | layer.emitterSize = CGSize(
98 | width: self.font.pointSize,
99 | height: 1
100 | )
101 | layer.emitterPosition = CGPoint(
102 | x: centerRect.origin.x,
103 | y: centerRect.origin.y + centerRect.size.height / 1.3
104 | )
105 | cell.scale = self.font.pointSize / 90.0
106 | cell.scaleSpeed = self.font.pointSize / 40.0
107 | cell.color = self.textColor.cgColor
108 | cell.birthRate = 60
109 | cell.velocity = 350
110 | cell.yAcceleration = 0
111 | cell.xAcceleration = CGFloat(10 * Int(arc4random_uniform(10)))
112 | cell.emissionLongitude = CGFloat(-Double.pi / 2)
113 | cell.emissionRange = CGFloat(Double.pi / 4) / 5.0
114 | cell.alphaSpeed = -2
115 | cell.lifetime = self.morphingDuration
116 | }
117 |
118 | _ = self.emitterView.createEmitter(
119 | "rightFragments",
120 | particleName: "Fragment",
121 | duration: 0.6
122 | ) { (layer, cell) in
123 | layer.emitterSize = CGSize(
124 | width: self.font.pointSize,
125 | height: 1
126 | )
127 | layer.emitterPosition = CGPoint(
128 | x: centerRect.origin.x,
129 | y: centerRect.origin.y + centerRect.size.height / 1.3)
130 | cell.scale = self.font.pointSize / 90.0
131 | cell.scaleSpeed = self.font.pointSize / 40.0
132 | cell.color = self.textColor.cgColor
133 | cell.birthRate = 60
134 | cell.velocity = 350
135 | cell.yAcceleration = 0
136 | cell.xAcceleration = CGFloat(-10 * Int(arc4random_uniform(10)))
137 | cell.emissionLongitude = CGFloat(Double.pi / 2)
138 | cell.emissionRange = CGFloat(-Double.pi / 4) / 5.0
139 | cell.alphaSpeed = -2
140 | cell.lifetime = self.morphingDuration
141 | }
142 |
143 | _ = self.emitterView.createEmitter(
144 | "fragments",
145 | particleName: "Fragment",
146 | duration: 0.6
147 | ) { (layer, cell) in
148 | layer.emitterSize = CGSize(
149 | width: self.font.pointSize,
150 | height: 1
151 | )
152 | layer.emitterPosition = CGPoint(
153 | x: centerRect.origin.x,
154 | y: centerRect.origin.y + centerRect.size.height / 1.3)
155 | cell.scale = self.font.pointSize / 90.0
156 | cell.scaleSpeed = self.font.pointSize / 40.0
157 | cell.color = self.textColor.cgColor
158 | cell.birthRate = 60
159 | cell.velocity = 250
160 | cell.velocityRange = CGFloat(Int(arc4random_uniform(20)) + 30)
161 | cell.yAcceleration = 500
162 | cell.emissionLongitude = 0
163 | cell.emissionRange = CGFloat(Double.pi / 2)
164 | cell.alphaSpeed = -1
165 | cell.lifetime = self.morphingDuration
166 | }
167 | }
168 |
169 | progressClosures["Anvil\(LTMorphingPhases.progress)"] = {
170 | (index: Int, progress: Float, isNewChar: Bool) in
171 |
172 | if !isNewChar {
173 | return min(1.0, max(0.0, progress))
174 | }
175 |
176 | let j = Float(sin(Float(index))) * 1.7
177 | return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * j))
178 |
179 | }
180 |
181 | effectClosures["Anvil\(LTMorphingPhases.disappear)"] = {
182 | char, index, progress in
183 |
184 | return LTCharacterLimbo(
185 | char: char,
186 | rect: self.previousRects[index],
187 | alpha: CGFloat(1.0 - progress),
188 | size: self.font.pointSize,
189 | drawingProgress: 0.0)
190 | }
191 |
192 | effectClosures["Anvil\(LTMorphingPhases.appear)"] = {
193 | char, index, progress in
194 |
195 | var rect = self.newRects[index]
196 |
197 | if progress < 1.0 {
198 | let easingValue = LTEasing.easeOutBounce(progress, 0.0, 1.0)
199 | rect.origin.y = CGFloat(Float(rect.origin.y) * easingValue)
200 | }
201 |
202 | if progress > self.morphingDuration * 0.5 {
203 | let end = self.morphingDuration * 0.55
204 | self.emitterView.createEmitter(
205 | "fragments",
206 | particleName: "Fragment",
207 | duration: 0.6
208 | ) { (_, _) in }.update { (layer, _) in
209 | if progress > end {
210 | layer.birthRate = 0
211 | }
212 | }.play()
213 | self.emitterView.createEmitter(
214 | "leftFragments",
215 | particleName: "Fragment",
216 | duration: 0.6
217 | ) { (_, _) in }.update { (layer, _) in
218 | if progress > end {
219 | layer.birthRate = 0
220 | }
221 | }.play()
222 | self.emitterView.createEmitter(
223 | "rightFragments",
224 | particleName: "Fragment",
225 | duration: 0.6
226 | ) { (_, _) in }.update { (layer, _) in
227 | if progress > end {
228 | layer.birthRate = 0
229 | }
230 | }.play()
231 | }
232 |
233 | if progress > self.morphingDuration * 0.63 {
234 | let end = self.morphingDuration * 0.7
235 | self.emitterView.createEmitter(
236 | "leftSmoke",
237 | particleName: "Smoke",
238 | duration: 0.6
239 | ) { (_, _) in }.update { (layer, _) in
240 | if progress > end {
241 | layer.birthRate = 0
242 | }
243 | }.play()
244 | self.emitterView.createEmitter(
245 | "rightSmoke",
246 | particleName: "Smoke",
247 | duration: 0.6
248 | ) { (_, _) in }.update { (layer, _) in
249 | if progress > end {
250 | layer.birthRate = 0
251 | }
252 | }.play()
253 | }
254 |
255 | return LTCharacterLimbo(
256 | char: char,
257 | rect: rect,
258 | alpha: CGFloat(self.morphingProgress),
259 | size: self.font.pointSize,
260 | drawingProgress: CGFloat(progress)
261 | )
262 | }
263 | }
264 |
265 | }
266 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Burn.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Burn.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | fileprivate func burningImageForCharLimbo(
33 | _ charLimbo: LTCharacterLimbo,
34 | withProgress progress: CGFloat
35 | ) -> (UIImage, CGRect) {
36 | let maskedHeight = charLimbo.rect.size.height * max(0.01, progress)
37 | let maskedSize = CGSize(
38 | width: charLimbo.rect.size.width,
39 | height: maskedHeight
40 | )
41 | UIGraphicsBeginImageContextWithOptions(
42 | maskedSize,
43 | false,
44 | UIScreen.main.scale
45 | )
46 | let rect = CGRect(
47 | x: 0,
48 | y: 0,
49 | width: charLimbo.rect.size.width,
50 | height: maskedHeight
51 | )
52 | String(charLimbo.char).draw(in: rect, withAttributes: [
53 | .font: self.font as Any,
54 | .foregroundColor: self.textColor as Any
55 | ])
56 | guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
57 | return (UIImage() , .zero)
58 | }
59 |
60 | UIGraphicsEndImageContext()
61 | let newRect = CGRect(
62 | x: charLimbo.rect.origin.x,
63 | y: charLimbo.rect.origin.y,
64 | width: charLimbo.rect.size.width,
65 | height: maskedHeight
66 | )
67 | return (newImage, newRect)
68 | }
69 |
70 | @objc
71 | func BurnLoad() {
72 |
73 | startClosures["Burn\(LTMorphingPhases.start)"] = {
74 | self.emitterView.removeAllEmitters()
75 | }
76 |
77 | progressClosures["Burn\(LTMorphingPhases.progress)"] = {
78 | index, progress, isNewChar in
79 |
80 | if !isNewChar {
81 | return min(1.0, max(0.0, progress))
82 | }
83 |
84 | let j = Float(sin(Float(index))) * 1.5
85 | return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * j))
86 |
87 | }
88 |
89 | effectClosures["Burn\(LTMorphingPhases.disappear)"] = {
90 | char, index, progress in
91 |
92 | return LTCharacterLimbo(
93 | char: char,
94 | rect: self.previousRects[index],
95 | alpha: CGFloat(1.0 - progress),
96 | size: self.font.pointSize,
97 | drawingProgress: 0.0
98 | )
99 | }
100 |
101 | effectClosures["Burn\(LTMorphingPhases.appear)"] = {
102 | char, index, progress in
103 |
104 | if char != " " {
105 | let rect = self.newRects[index]
106 | let emitterPosition = CGPoint(
107 | x: rect.origin.x + rect.size.width / 2.0,
108 | y: CGFloat(progress) * rect.size.height / 1.2 + rect.origin.y
109 | )
110 |
111 | self.emitterView.createEmitter(
112 | "c\(index)",
113 | particleName: "Fire",
114 | duration: self.morphingDuration
115 | ) { (layer, cell) in
116 | layer.emitterSize = CGSize(
117 | width: rect.size.width,
118 | height: 1
119 | )
120 | layer.renderMode = CAEmitterLayerRenderMode.additive
121 | layer.emitterMode = CAEmitterLayerEmitterMode.outline
122 | cell.emissionLongitude = CGFloat(Double.pi / 2)
123 | cell.scale = self.font.pointSize / 160.0
124 | cell.scaleSpeed = self.font.pointSize / 100.0
125 | cell.birthRate = Float(self.font.pointSize)
126 | cell.emissionLongitude = CGFloat(arc4random_uniform(30))
127 | cell.emissionRange = CGFloat(Double.pi / 4)
128 | cell.alphaSpeed = self.morphingDuration * -3.0
129 | cell.yAcceleration = 10
130 | cell.velocity = CGFloat(10 + Int(arc4random_uniform(3)))
131 | cell.velocityRange = 10
132 | cell.spin = 0
133 | cell.spinRange = 0
134 | cell.lifetime = self.morphingDuration / 3.0
135 | }.update { (layer, _) in
136 | layer.emitterPosition = emitterPosition
137 | }.play()
138 |
139 | self.emitterView.createEmitter(
140 | "s\(index)",
141 | particleName: "Smoke",
142 | duration: self.morphingDuration
143 | ) { (layer, cell) in
144 | layer.emitterSize = CGSize(
145 | width: rect.size.width,
146 | height: 10
147 | )
148 | layer.renderMode = CAEmitterLayerRenderMode.additive
149 | layer.emitterMode = CAEmitterLayerEmitterMode.volume
150 | cell.emissionLongitude = CGFloat(Double.pi / 2)
151 | cell.scale = self.font.pointSize / 40.0
152 | cell.scaleSpeed = self.font.pointSize / 100.0
153 | cell.birthRate =
154 | Float(self.font.pointSize)
155 | / Float(arc4random_uniform(10) + 10)
156 | cell.emissionLongitude = 0
157 | cell.emissionRange = CGFloat(Double.pi / 4)
158 | cell.alphaSpeed = self.morphingDuration * -3
159 | cell.yAcceleration = -5
160 | cell.velocity = CGFloat(20 + Int(arc4random_uniform(15)))
161 | cell.velocityRange = 20
162 | cell.spin = CGFloat(Float(arc4random_uniform(30)) / 10.0)
163 | cell.spinRange = 3
164 | cell.lifetime = self.morphingDuration
165 | }.update { (layer, _) in
166 | layer.emitterPosition = emitterPosition
167 | }.play()
168 | }
169 |
170 | return LTCharacterLimbo(
171 | char: char,
172 | rect: self.newRects[index],
173 | alpha: 1.0,
174 | size: self.font.pointSize,
175 | drawingProgress: CGFloat(progress)
176 | )
177 | }
178 |
179 | drawingClosures["Burn\(LTMorphingPhases.draw)"] = {
180 | (charLimbo: LTCharacterLimbo) in
181 |
182 | if charLimbo.drawingProgress > 0.0 {
183 |
184 | let (charImage, rect) = self.burningImageForCharLimbo(
185 | charLimbo,
186 | withProgress: charLimbo.drawingProgress
187 | )
188 | charImage.draw(in: rect)
189 |
190 | return true
191 | }
192 |
193 | return false
194 | }
195 |
196 | skipFramesClosures["Burn\(LTMorphingPhases.skipFrames)"] = {
197 | return 1
198 | }
199 | }
200 |
201 | }
202 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Evaporate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Evaporate.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | @objc
33 | func EvaporateLoad() {
34 |
35 | progressClosures["Evaporate\(LTMorphingPhases.progress)"] = {
36 | (index: Int, _, isNewChar: Bool) in
37 | let j: Int = Int(round(cos(Double(index)) * 1.2))
38 | let delay = isNewChar ? self.morphingCharacterDelay * -1.0 : self.morphingCharacterDelay
39 | return min(1.0, max(0.0, self.morphingProgress + delay * Float(j)))
40 | }
41 |
42 | effectClosures["Evaporate\(LTMorphingPhases.disappear)"] = {
43 | char, index, progress in
44 |
45 | let newProgress = LTEasing.easeOutQuint(progress, 0.0, 1.0, 1.0)
46 | let yOffset: CGFloat = -0.8 * CGFloat(self.font.pointSize) * CGFloat(newProgress)
47 | let currentRect = self.previousRects[index].offsetBy(dx: 0, dy: yOffset)
48 | let currentAlpha = CGFloat(1.0 - newProgress)
49 |
50 | return LTCharacterLimbo(
51 | char: char,
52 | rect: currentRect,
53 | alpha: currentAlpha,
54 | size: self.font.pointSize,
55 | drawingProgress: 0.0)
56 | }
57 |
58 | effectClosures["Evaporate\(LTMorphingPhases.appear)"] = {
59 | char, index, progress in
60 |
61 | let newProgress = 1.0 - LTEasing.easeOutQuint(progress, 0.0, 1.0)
62 | let yOffset = CGFloat(self.font.pointSize) * CGFloat(newProgress) * 1.2
63 |
64 | return LTCharacterLimbo(
65 | char: char,
66 | rect: self.newRects[index].offsetBy(dx: 0, dy: yOffset),
67 | alpha: CGFloat(self.morphingProgress),
68 | size: self.font.pointSize,
69 | drawingProgress: 0.0
70 | )
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Fall.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Fall.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | @objc
33 | func FallLoad() {
34 |
35 | progressClosures["Fall\(LTMorphingPhases.progress)"] = {
36 | (index: Int, progress: Float, isNewChar: Bool) in
37 |
38 | if isNewChar {
39 | return min(
40 | 1.0,
41 | max(
42 | 0.0,
43 | progress
44 | - self.morphingCharacterDelay
45 | * Float(index)
46 | / 1.7
47 | )
48 | )
49 | }
50 |
51 | let j: Float = Float(sin(Double(index))) * 1.7
52 | return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * Float(j)))
53 |
54 | }
55 |
56 | effectClosures["Fall\(LTMorphingPhases.disappear)"] = {
57 | char, index, progress in
58 |
59 | return LTCharacterLimbo(
60 | char: char,
61 | rect: self.previousRects[index],
62 | alpha: CGFloat(1.0 - progress),
63 | size: self.font.pointSize,
64 | drawingProgress: CGFloat(progress))
65 | }
66 |
67 | effectClosures["Fall\(LTMorphingPhases.appear)"] = {
68 | char, index, progress in
69 |
70 | let currentFontSize = CGFloat(
71 | LTEasing.easeOutQuint(progress, 0.0, Float(self.font.pointSize))
72 | )
73 | let yOffset = CGFloat(self.font.pointSize - currentFontSize)
74 |
75 | return LTCharacterLimbo(
76 | char: char,
77 | rect: self.newRects[index].offsetBy(dx: 0, dy: yOffset),
78 | alpha: CGFloat(self.morphingProgress),
79 | size: currentFontSize,
80 | drawingProgress: 0.0
81 | )
82 | }
83 |
84 | drawingClosures["Fall\(LTMorphingPhases.draw)"] = {
85 | limbo in
86 |
87 | if limbo.drawingProgress > 0.0 {
88 | let context = UIGraphicsGetCurrentContext()
89 | var charRect = limbo.rect
90 | context!.saveGState()
91 | let charCenterX = charRect.origin.x + (charRect.size.width / 2.0)
92 | var charBottomY = charRect.origin.y + charRect.size.height - self.font.pointSize / 6
93 | var charColor: UIColor = self.textColor
94 |
95 | // Fall down if drawingProgress is more than 50%
96 | if limbo.drawingProgress > 0.5 {
97 | let ease = CGFloat(
98 | LTEasing.easeInQuint(
99 | Float(limbo.drawingProgress - 0.4),
100 | 0.0,
101 | 1.0,
102 | 0.5
103 | )
104 | )
105 | charBottomY += ease * 10.0
106 | let fadeOutAlpha = min(
107 | 1.0,
108 | max(
109 | 0.0,
110 | limbo.drawingProgress * -2.0 + 2.0 + 0.01
111 | )
112 | )
113 | charColor = self.textColor.withAlphaComponent(fadeOutAlpha)
114 | }
115 |
116 | charRect = CGRect(
117 | x: charRect.size.width / -2.0,
118 | y: charRect.size.height * -1.0 + self.font.pointSize / 6,
119 | width: charRect.size.width,
120 | height: charRect.size.height)
121 | context!.translateBy(x: charCenterX, y: charBottomY)
122 |
123 | let angle = Float(sin(Double(limbo.rect.origin.x)) > 0.5 ? 168 : -168)
124 | let rotation = CGFloat(
125 | LTEasing.easeOutBack(
126 | min(
127 | 1.0,
128 | Float(limbo.drawingProgress)
129 | ),
130 | 0.0,
131 | 1.0
132 | ) * angle
133 | )
134 | context!.rotate(by: rotation * CGFloat(Double.pi) / 180.0)
135 | let s = String(limbo.char)
136 | let attributes: [NSAttributedString.Key: Any] = [
137 | .font: self.font.withSize(limbo.size),
138 | .foregroundColor: charColor
139 | ]
140 | s.draw(in: charRect, withAttributes: attributes)
141 | context!.restoreGState()
142 |
143 | return true
144 | }
145 |
146 | return false
147 | }
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Pixelate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Pixelate.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | @objc
33 | func PixelateLoad() {
34 |
35 | effectClosures["Pixelate\(LTMorphingPhases.disappear)"] = {
36 | char, index, progress in
37 |
38 | return LTCharacterLimbo(
39 | char: char,
40 | rect: self.previousRects[index],
41 | alpha: CGFloat(1.0 - progress),
42 | size: self.font.pointSize,
43 | drawingProgress: CGFloat(progress))
44 | }
45 |
46 | effectClosures["Pixelate\(LTMorphingPhases.appear)"] = {
47 | char, index, progress in
48 |
49 | return LTCharacterLimbo(
50 | char: char,
51 | rect: self.newRects[index],
52 | alpha: CGFloat(progress),
53 | size: self.font.pointSize,
54 | drawingProgress: CGFloat(1.0 - progress)
55 | )
56 | }
57 |
58 | drawingClosures["Pixelate\(LTMorphingPhases.draw)"] = {
59 | limbo in
60 |
61 | if limbo.drawingProgress > 0.0 {
62 |
63 | let charImage = self.pixelateImageForCharLimbo(
64 | limbo,
65 | withBlurRadius: limbo.drawingProgress * 6.0
66 | )
67 |
68 | charImage.draw(in: limbo.rect)
69 |
70 | return true
71 | }
72 |
73 | return false
74 | }
75 | }
76 |
77 | fileprivate func pixelateImageForCharLimbo(
78 | _ charLimbo: LTCharacterLimbo,
79 | withBlurRadius blurRadius: CGFloat
80 | ) -> UIImage {
81 | let scale = min(UIScreen.main.scale, 1.0 / blurRadius)
82 | UIGraphicsBeginImageContextWithOptions(charLimbo.rect.size, false, scale)
83 | let fadeOutAlpha = min(1.0, max(0.0, charLimbo.drawingProgress * -2.0 + 2.0 + 0.01))
84 | let rect = CGRect(
85 | x: 0,
86 | y: 0,
87 | width: charLimbo.rect.size.width,
88 | height: charLimbo.rect.size.height
89 | )
90 | String(charLimbo.char).draw(in: rect, withAttributes: [
91 | .font: self.font as Any,
92 | .foregroundColor: self.textColor.withAlphaComponent(fadeOutAlpha)
93 | ])
94 | guard let newImage = UIGraphicsGetImageFromCurrentImageContext()
95 | else {
96 | return UIImage()
97 | }
98 | UIGraphicsEndImageContext()
99 | return newImage
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel+Sparkle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel+Sparkle.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import UIKit
29 |
30 | extension LTMorphingLabel {
31 |
32 | fileprivate func maskedImageForCharLimbo(
33 | _ charLimbo: LTCharacterLimbo,
34 | withProgress progress: CGFloat
35 | ) -> (UIImage, CGRect) {
36 | let maskedHeight = charLimbo.rect.size.height * max(0.01, progress)
37 | let maskedSize = CGSize(
38 | width: charLimbo.rect.size.width,
39 | height: maskedHeight
40 | )
41 | UIGraphicsBeginImageContextWithOptions(
42 | maskedSize,
43 | false,
44 | UIScreen.main.scale
45 | )
46 | let rect = CGRect(
47 | x: 0,
48 | y: 0,
49 | width: charLimbo.rect.size.width,
50 | height: maskedHeight
51 | )
52 | String(charLimbo.char).draw(in: rect, withAttributes: [
53 | .font: self.font as Any,
54 | .foregroundColor: self.textColor as Any
55 | ])
56 | guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
57 | return (UIImage(), CGRect.zero)
58 | }
59 | UIGraphicsEndImageContext()
60 | let newRect = CGRect(
61 | x: charLimbo.rect.origin.x,
62 | y: charLimbo.rect.origin.y,
63 | width: charLimbo.rect.size.width,
64 | height: maskedHeight
65 | )
66 | return (newImage, newRect)
67 | }
68 |
69 | @objc
70 | func SparkleLoad() {
71 |
72 | startClosures["Sparkle\(LTMorphingPhases.start)"] = {
73 | self.emitterView.removeAllEmitters()
74 | }
75 |
76 | progressClosures["Sparkle\(LTMorphingPhases.progress)"] = {
77 | (index: Int, progress: Float, isNewChar: Bool) in
78 |
79 | if !isNewChar {
80 | return min(1.0, max(0.0, progress))
81 | }
82 |
83 | let j = Float(sin(Float(index))) * 1.5
84 | return min(
85 | 1.0,
86 | max(
87 | 0.0001,
88 | progress + self.morphingCharacterDelay * j
89 | )
90 | )
91 |
92 | }
93 |
94 | effectClosures["Sparkle\(LTMorphingPhases.disappear)"] = {
95 | char, index, progress in
96 |
97 | return LTCharacterLimbo(
98 | char: char,
99 | rect: self.previousRects[index],
100 | alpha: CGFloat(1.0 - progress),
101 | size: self.font.pointSize,
102 | drawingProgress: 0.0)
103 | }
104 |
105 | effectClosures["Sparkle\(LTMorphingPhases.appear)"] = {
106 | char, index, progress in
107 |
108 | if char != " " {
109 | let rect = self.newRects[index]
110 | let emitterPosition = CGPoint(
111 | x: rect.origin.x + rect.size.width / 2.0,
112 | y: CGFloat(progress) * rect.size.height * 0.9 + rect.origin.y
113 | )
114 |
115 | self.emitterView.createEmitter(
116 | "c\(index)",
117 | particleName: "Sparkle",
118 | duration: self.morphingDuration
119 | ) { (layer, cell) in
120 | layer.emitterSize = CGSize(
121 | width: rect.size.width,
122 | height: 1
123 | )
124 | layer.renderMode = .unordered
125 | cell.emissionLongitude = CGFloat(Double.pi / 2.0)
126 | cell.scale = self.font.pointSize / 300.0
127 | cell.scaleSpeed = self.font.pointSize / 300.0 * -1.5
128 | cell.color = self.textColor.cgColor
129 | cell.birthRate =
130 | Float(self.font.pointSize)
131 | * Float(arc4random_uniform(7) + 3)
132 | }.update { (layer, _) in
133 | layer.emitterPosition = emitterPosition
134 | }.play()
135 | }
136 |
137 | return LTCharacterLimbo(
138 | char: char,
139 | rect: self.newRects[index],
140 | alpha: CGFloat(self.morphingProgress),
141 | size: self.font.pointSize,
142 | drawingProgress: CGFloat(progress)
143 | )
144 | }
145 |
146 | drawingClosures["Sparkle\(LTMorphingPhases.draw)"] = {
147 | (charLimbo: LTCharacterLimbo) in
148 |
149 | if charLimbo.drawingProgress > 0.0 {
150 |
151 | let (charImage, rect) = self.maskedImageForCharLimbo(
152 | charLimbo,
153 | withProgress: charLimbo.drawingProgress
154 | )
155 | charImage.draw(in: rect)
156 |
157 | return true
158 | }
159 |
160 | return false
161 | }
162 |
163 | skipFramesClosures["Sparkle\(LTMorphingPhases.skipFrames)"] = {
164 | return 1
165 | }
166 | }
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel.h
3 | // LTMorphingLabel
4 | //
5 | // Created by Lex Tang on 1/8/15.
6 | // Copyright (c) 2015 lexrus.com. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for LTMorphingLabel.
12 | FOUNDATION_EXPORT double LTMorphingLabelVersionNumber;
13 |
14 | //! Project version string for LTMorphingLabel.
15 | FOUNDATION_EXPORT const unsigned char LTMorphingLabelVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTMorphingLabel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabel.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import Foundation
29 | import UIKit
30 | import QuartzCore
31 |
32 | private func < (lhs: T?, rhs: T?) -> Bool {
33 | switch (lhs, rhs) {
34 | case let (l?, r?):
35 | return l < r
36 | case (nil, _?):
37 | return true
38 | default:
39 | return false
40 | }
41 | }
42 |
43 | private func >= (lhs: T?, rhs: T?) -> Bool {
44 | switch (lhs, rhs) {
45 | case let (l?, r?):
46 | return l >= r
47 | default:
48 | return !(lhs < rhs)
49 | }
50 | }
51 |
52 | enum LTMorphingPhases: Int {
53 | case start, appear, disappear, draw, progress, skipFrames
54 | }
55 |
56 | typealias LTMorphingStartClosure =
57 | () -> Void
58 |
59 | typealias LTMorphingEffectClosure =
60 | (Character, _ index: Int, _ progress: Float) -> LTCharacterLimbo
61 |
62 | typealias LTMorphingDrawingClosure =
63 | (LTCharacterLimbo) -> Bool
64 |
65 | typealias LTMorphingManipulateProgressClosure =
66 | (_ index: Int, _ progress: Float, _ isNewChar: Bool) -> Float
67 |
68 | typealias LTMorphingSkipFramesClosure =
69 | () -> Int
70 |
71 | @objc public protocol LTMorphingLabelDelegate {
72 | @objc optional func morphingDidStart(_ label: LTMorphingLabel)
73 | @objc optional func morphingDidComplete(_ label: LTMorphingLabel)
74 | @objc optional func morphingOnProgress(_ label: LTMorphingLabel, progress: Float)
75 | }
76 |
77 | // MARK: - LTMorphingLabel
78 | @IBDesignable open class LTMorphingLabel: UILabel {
79 |
80 | @IBInspectable open var morphingProgress: Float = 0.0
81 | @IBInspectable open var morphingDuration: Float = 0.6
82 | @IBInspectable open var morphingCharacterDelay: Float = 0.026
83 | @IBInspectable open var morphingEnabled: Bool = true
84 |
85 | @IBOutlet open weak var delegate: LTMorphingLabelDelegate?
86 | open var morphingEffect: LTMorphingEffect = .scale
87 |
88 | var startClosures = [String: LTMorphingStartClosure]()
89 | var effectClosures = [String: LTMorphingEffectClosure]()
90 | var drawingClosures = [String: LTMorphingDrawingClosure]()
91 | var progressClosures = [String: LTMorphingManipulateProgressClosure]()
92 | var skipFramesClosures = [String: LTMorphingSkipFramesClosure]()
93 | var diffResults: LTStringDiffResult?
94 | var previousText = ""
95 |
96 | var currentFrame = 0
97 | var totalFrames = 0
98 | var totalDelayFrames = 0
99 |
100 | var totalWidth: Float = 0.0
101 | var previousRects = [CGRect]()
102 | var newRects = [CGRect]()
103 | var charHeight: CGFloat = 0.0
104 | var skipFramesCount: Int = 0
105 |
106 | fileprivate var displayLink: CADisplayLink?
107 |
108 | private var tempRenderMorphingEnabled = true
109 |
110 | #if TARGET_INTERFACE_BUILDER
111 | let presentingInIB = true
112 | #else
113 | let presentingInIB = false
114 | #endif
115 |
116 | override open var font: UIFont! {
117 | get {
118 | return super.font ?? UIFont.systemFont(ofSize: 15)
119 | }
120 | set {
121 | super.font = newValue
122 | setNeedsLayout()
123 | }
124 | }
125 |
126 | override open var text: String? {
127 | get {
128 | return super.text ?? ""
129 | }
130 | set {
131 | guard text != newValue else { return }
132 |
133 | previousText = text ?? ""
134 | diffResults = previousText.diffWith(newValue)
135 | super.text = newValue ?? ""
136 |
137 | morphingProgress = 0.0
138 | currentFrame = 0
139 | totalFrames = 0
140 |
141 | tempRenderMorphingEnabled = morphingEnabled
142 | setNeedsLayout()
143 |
144 | if !morphingEnabled {
145 | return
146 | }
147 |
148 | if presentingInIB {
149 | morphingDuration = 0.01
150 | morphingProgress = 0.5
151 | } else if previousText != text {
152 | start()
153 | let closureKey = "\(morphingEffect.description)\(LTMorphingPhases.start)"
154 | if let closure = startClosures[closureKey] {
155 | return closure()
156 | }
157 |
158 | delegate?.morphingDidStart?(self)
159 | }
160 | }
161 | }
162 |
163 | open func start() {
164 | guard displayLink == nil else { return }
165 | displayLink = CADisplayLink(target: self, selector: #selector(displayFrameTick))
166 | displayLink?.add(to: .current, forMode: .common)
167 | }
168 |
169 | open func pause() {
170 | displayLink?.isPaused = true
171 | }
172 |
173 | open func resume() {
174 | displayLink?.isPaused = false
175 | }
176 |
177 | open func finish() {
178 | displayLink?.isPaused = false
179 | }
180 |
181 | open func stop() {
182 | displayLink?.remove(from: .current, forMode: .common)
183 | displayLink?.invalidate()
184 | displayLink = nil
185 | }
186 |
187 | open var textAttributes: [NSAttributedString.Key: Any]? {
188 | didSet {
189 | setNeedsLayout()
190 | }
191 | }
192 |
193 | open override func setNeedsLayout() {
194 | super.setNeedsLayout()
195 | previousRects = rectsOfEachCharacter(previousText, withFont: font)
196 | newRects = rectsOfEachCharacter(text ?? "", withFont: font)
197 | }
198 |
199 | override open var bounds: CGRect {
200 | get {
201 | return super.bounds
202 | }
203 | set {
204 | super.bounds = newValue
205 | setNeedsLayout()
206 | }
207 | }
208 |
209 | override open var frame: CGRect {
210 | get {
211 | return super.frame
212 | }
213 | set {
214 | super.frame = newValue
215 | setNeedsLayout()
216 | }
217 | }
218 |
219 | deinit {
220 | stop()
221 | }
222 |
223 | lazy var emitterView: LTEmitterView = {
224 | let emitterView = LTEmitterView(frame: self.bounds)
225 | self.addSubview(emitterView)
226 | return emitterView
227 | }()
228 | }
229 |
230 | // MARK: - Animation extension
231 | extension LTMorphingLabel {
232 |
233 | public func updateProgress(progress: Float) {
234 | guard let displayLink = displayLink else { return }
235 |
236 | if displayLink.duration > 0.0 && totalFrames == 0 {
237 | var frameRate = Float(0)
238 | if #available(iOS 10.0, tvOS 10.0, *) {
239 | var frameInterval = 1
240 | if displayLink.preferredFramesPerSecond == 60 {
241 | frameInterval = 1
242 | } else if displayLink.preferredFramesPerSecond == 30 {
243 | frameInterval = 2
244 | } else {
245 | frameInterval = 1
246 | }
247 | frameRate = Float(displayLink.duration) / Float(frameInterval)
248 | } else {
249 | frameRate = Float(displayLink.duration) / Float(displayLink.frameInterval)
250 | }
251 | totalFrames = Int(ceil(morphingDuration / frameRate))
252 |
253 | let totalDelay = Float((text!).count) * morphingCharacterDelay
254 | totalDelayFrames = Int(ceil(totalDelay / frameRate))
255 | }
256 |
257 | currentFrame = Int(ceil(progress * Float(totalFrames)))
258 |
259 | if previousText != text && currentFrame < totalFrames + totalDelayFrames + 10 {
260 | morphingProgress = progress
261 |
262 | let closureKey = "\(morphingEffect.description)\(LTMorphingPhases.skipFrames)"
263 | if let closure = skipFramesClosures[closureKey] {
264 | skipFramesCount += 1
265 | if skipFramesCount > closure() {
266 | skipFramesCount = 0
267 | setNeedsDisplay()
268 | }
269 | } else {
270 | setNeedsDisplay()
271 | }
272 |
273 | if let onProgress = delegate?.morphingOnProgress {
274 | onProgress(self, morphingProgress)
275 | }
276 | } else {
277 | stop()
278 |
279 | delegate?.morphingDidComplete?(self)
280 | }
281 | }
282 |
283 | @objc func displayFrameTick() {
284 | if totalFrames == 0 {
285 | updateProgress(progress: 0)
286 | } else {
287 | morphingProgress += 1.0 / Float(totalFrames)
288 | updateProgress(progress: morphingProgress)
289 | }
290 | }
291 |
292 | // Could be enhanced by kerning text:
293 | // http://stackoverflow.com/questions/21443625/core-text-calculate-letter-frame-in-ios
294 | func rectsOfEachCharacter(_ textToDraw: String, withFont font: UIFont) -> [CGRect] {
295 | var charRects = [CGRect]()
296 | var leftOffset: CGFloat = 0.0
297 |
298 | charHeight = "Leg".size(withAttributes: [.font: font]).height
299 |
300 | let topOffset = (bounds.size.height - charHeight) / 2.0
301 |
302 | for char in textToDraw {
303 | let charSize = String(char).size(withAttributes: [.font: font])
304 | charRects.append(
305 | CGRect(
306 | origin: CGPoint(
307 | x: leftOffset,
308 | y: topOffset
309 | ),
310 | size: charSize
311 | )
312 | )
313 | leftOffset += charSize.width
314 | }
315 |
316 | totalWidth = Float(leftOffset)
317 |
318 | var stringLeftOffSet: CGFloat = 0.0
319 |
320 | switch textAlignment {
321 | case .center:
322 | stringLeftOffSet = CGFloat((Float(bounds.size.width) - totalWidth) / 2.0)
323 | case .right:
324 | stringLeftOffSet = CGFloat(Float(bounds.size.width) - totalWidth)
325 | default:
326 | ()
327 | }
328 |
329 | var offsetedCharRects = [CGRect]()
330 |
331 | for r in charRects {
332 | offsetedCharRects.append(r.offsetBy(dx: stringLeftOffSet, dy: 0.0))
333 | }
334 |
335 | return offsetedCharRects
336 | }
337 |
338 | func limboOfOriginalCharacter(
339 | _ char: Character,
340 | index: Int,
341 | progress: Float) -> LTCharacterLimbo {
342 |
343 | var currentRect = previousRects[index]
344 | let oriX = Float(currentRect.origin.x)
345 | var newX = Float(currentRect.origin.x)
346 | let diffResult = diffResults!.0[index]
347 | var currentFontSize: CGFloat = font.pointSize
348 | var currentAlpha: CGFloat = 1.0
349 |
350 | switch diffResult {
351 | // Move the character that exists in the new text to current position
352 | case .same:
353 | newX = Float(newRects[index].origin.x)
354 | currentRect.origin.x = CGFloat(
355 | LTEasing.easeOutQuint(progress, oriX, newX - oriX)
356 | )
357 | case .move(let offset):
358 | newX = Float(newRects[index + offset].origin.x)
359 | currentRect.origin.x = CGFloat(
360 | LTEasing.easeOutQuint(progress, oriX, newX - oriX)
361 | )
362 | case .moveAndAdd(let offset):
363 | newX = Float(newRects[index + offset].origin.x)
364 | currentRect.origin.x = CGFloat(
365 | LTEasing.easeOutQuint(progress, oriX, newX - oriX)
366 | )
367 | default:
368 | // Otherwise, remove it
369 |
370 | // Override morphing effect with closure in extenstions
371 | if let closure = effectClosures[
372 | "\(morphingEffect.description)\(LTMorphingPhases.disappear)"
373 | ] {
374 | return closure(char, index, progress)
375 | } else {
376 | // And scale it by default
377 | let fontEase = CGFloat(
378 | LTEasing.easeOutQuint(
379 | progress, 0, Float(font.pointSize)
380 | )
381 | )
382 | // For emojis
383 | currentFontSize = max(0.0001, font.pointSize - fontEase)
384 | currentAlpha = CGFloat(1.0 - progress)
385 | currentRect = previousRects[index].offsetBy(
386 | dx: 0,
387 | dy: CGFloat(font.pointSize - currentFontSize)
388 | )
389 | }
390 | }
391 |
392 | return LTCharacterLimbo(
393 | char: char,
394 | rect: currentRect,
395 | alpha: currentAlpha,
396 | size: currentFontSize,
397 | drawingProgress: 0.0
398 | )
399 | }
400 |
401 | func limboOfNewCharacter(
402 | _ char: Character,
403 | index: Int,
404 | progress: Float) -> LTCharacterLimbo {
405 |
406 | let currentRect = newRects[index]
407 | var currentFontSize = CGFloat(
408 | LTEasing.easeOutQuint(progress, 0, Float(font.pointSize))
409 | )
410 |
411 | if let closure = effectClosures[
412 | "\(morphingEffect.description)\(LTMorphingPhases.appear)"
413 | ] {
414 | return closure(char, index, progress)
415 | } else {
416 | currentFontSize = CGFloat(
417 | LTEasing.easeOutQuint(progress, 0.0, Float(font.pointSize))
418 | )
419 | // For emojis
420 | currentFontSize = max(0.0001, currentFontSize)
421 |
422 | let yOffset = CGFloat(font.pointSize - currentFontSize)
423 |
424 | return LTCharacterLimbo(
425 | char: char,
426 | rect: currentRect.offsetBy(dx: 0, dy: yOffset),
427 | alpha: CGFloat(morphingProgress),
428 | size: currentFontSize,
429 | drawingProgress: 0.0
430 | )
431 | }
432 | }
433 |
434 | func limboOfCharacters() -> [LTCharacterLimbo] {
435 | var limbo = [LTCharacterLimbo]()
436 |
437 | // Iterate original characters
438 | for (i, character) in previousText.enumerated() {
439 | var progress: Float = 0.0
440 |
441 | if let closure = progressClosures[
442 | "\(morphingEffect.description)\(LTMorphingPhases.progress)"
443 | ] {
444 | progress = closure(i, morphingProgress, false)
445 | } else {
446 | progress = min(1.0, max(0.0, morphingProgress + morphingCharacterDelay * Float(i)))
447 | }
448 |
449 | let limboOfCharacter = limboOfOriginalCharacter(character, index: i, progress: progress)
450 | limbo.append(limboOfCharacter)
451 | }
452 |
453 | // Add new characters
454 | for (i, character) in (text!).enumerated() {
455 | if i >= diffResults?.0.count {
456 | break
457 | }
458 |
459 | var progress: Float = 0.0
460 |
461 | if let closure = progressClosures[
462 | "\(morphingEffect.description)\(LTMorphingPhases.progress)"
463 | ] {
464 | progress = closure(i, morphingProgress, true)
465 | } else {
466 | progress = min(1.0, max(0.0, morphingProgress - morphingCharacterDelay * Float(i)))
467 | }
468 |
469 | // Don't draw character that already exists
470 | if diffResults?.skipDrawingResults[i] == true {
471 | continue
472 | }
473 |
474 | if let diffResult = diffResults?.0[i] {
475 | switch diffResult {
476 | case .moveAndAdd, .replace, .add, .delete:
477 | let limboOfCharacter = limboOfNewCharacter(
478 | character,
479 | index: i,
480 | progress: progress
481 | )
482 | limbo.append(limboOfCharacter)
483 | default:
484 | ()
485 | }
486 | }
487 | }
488 |
489 | return limbo
490 | }
491 |
492 | }
493 |
494 | // MARK: - Drawing extension
495 | extension LTMorphingLabel {
496 |
497 | override open func didMoveToSuperview() {
498 | guard nil != superview else {
499 | stop()
500 | return
501 | }
502 |
503 | if let s = text {
504 | text = s
505 | }
506 |
507 | // Load all morphing effects
508 | for effectName: String in LTMorphingEffect.allValues {
509 | let effectFunc = Selector("\(effectName)Load")
510 | if responds(to: effectFunc) {
511 | perform(effectFunc)
512 | }
513 | }
514 | }
515 |
516 | override open func drawText(in rect: CGRect) {
517 | if !tempRenderMorphingEnabled || limboOfCharacters().count == 0 {
518 | super.drawText(in: rect)
519 | return
520 | }
521 |
522 | for charLimbo in limboOfCharacters() {
523 | let charRect = charLimbo.rect
524 |
525 | let willAvoidDefaultDrawing: Bool = {
526 | if let closure = drawingClosures[
527 | "\(morphingEffect.description)\(LTMorphingPhases.draw)"
528 | ] {
529 | return closure($0)
530 | }
531 | return false
532 | }(charLimbo)
533 |
534 | if !willAvoidDefaultDrawing {
535 | var attrs: [NSAttributedString.Key: Any] = [
536 | .foregroundColor: textColor.withAlphaComponent(charLimbo.alpha)
537 | ]
538 |
539 | attrs[.font] = UIFont(descriptor: font.fontDescriptor, size: charLimbo.size)
540 |
541 | for (key, value) in textAttributes ?? [:] {
542 | attrs[key] = value
543 | }
544 |
545 | let s = String(charLimbo.char)
546 | s.draw(in: charRect, withAttributes: attrs)
547 | }
548 | }
549 | }
550 |
551 | }
552 |
--------------------------------------------------------------------------------
/LTMorphingLabel/LTStringDiffResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTStringDiffResult.swift
3 | // https://github.com/lexrus/LTMorphingLabel
4 | //
5 | // The MIT License (MIT)
6 | // Copyright (c) 2017 Lex Tang, http://lexrus.com
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a
9 | // copy of this software and associated documentation files
10 | // (the “Software”), to deal in the Software without restriction,
11 | // including without limitation the rights to use, copy, modify, merge,
12 | // publish, distribute, sublicense, and/or sell copies of the Software,
13 | // and to permit persons to whom the Software is furnished to do so,
14 | // subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included
17 | // in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | import Foundation
29 |
30 | public typealias LTStringDiffResult = ([LTCharacterDiffResult], skipDrawingResults: [Bool])
31 |
32 | public extension String {
33 |
34 | func diffWith(_ anotherString: String?) -> LTStringDiffResult {
35 |
36 | guard let anotherString = anotherString else {
37 | let diffResults: [LTCharacterDiffResult] =
38 | Array(repeating: .delete, count: self.count)
39 | let skipDrawingResults: [Bool] = Array(repeating: false, count: self.count)
40 | return (diffResults, skipDrawingResults)
41 | }
42 |
43 | let newChars = anotherString.enumerated()
44 | let lhsLength = self.count
45 | let rhsLength = anotherString.count
46 | var skipIndexes = [Int]()
47 | let leftChars = Array(self)
48 |
49 | let maxLength = max(lhsLength, rhsLength)
50 | var diffResults: [LTCharacterDiffResult] = Array(repeating: .add, count: maxLength)
51 | var skipDrawingResults: [Bool] = Array(repeating: false, count: maxLength)
52 |
53 | for i in 0.. lhsLength - 1 {
56 | continue
57 | }
58 |
59 | let leftChar = leftChars[i]
60 |
61 | // Search left character in the new string
62 | var foundCharacterInRhs = false
63 | for (j, newChar) in newChars {
64 | if skipIndexes.contains(j) || leftChar != newChar {
65 | continue
66 | }
67 |
68 | skipIndexes.append(j)
69 | foundCharacterInRhs = true
70 | if i == j {
71 | // Character not changed
72 | diffResults[i] = .same
73 | } else {
74 | // foundCharacterInRhs and move
75 | let offset = j - i
76 |
77 | if i <= rhsLength - 1 {
78 | // Move to a new index and add a new character to new original place
79 | diffResults[i] = .moveAndAdd(offset: offset)
80 | } else {
81 | diffResults[i] = .move(offset: offset)
82 | }
83 |
84 | skipDrawingResults[j] = true
85 | }
86 | break
87 | }
88 |
89 | if !foundCharacterInRhs {
90 | if i < rhsLength - 1 {
91 | diffResults[i] = .replace
92 | } else {
93 | diffResults[i] = .delete
94 | }
95 | }
96 | }
97 |
98 | return (diffResults, skipDrawingResults)
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/LTMorphingLabel/Particles/Fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabel/Particles/Fire.png
--------------------------------------------------------------------------------
/LTMorphingLabel/Particles/Fragment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabel/Particles/Fragment.png
--------------------------------------------------------------------------------
/LTMorphingLabel/Particles/Smoke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabel/Particles/Smoke.png
--------------------------------------------------------------------------------
/LTMorphingLabel/Particles/Sparkle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabel/Particles/Sparkle.png
--------------------------------------------------------------------------------
/LTMorphingLabel/SwiftUI/MorphingText.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MorphingText.swift
3 | // LTMorphingLabel
4 | //
5 | // Created by Lex on 2020/5/10.
6 | // Copyright © 2020 lexrus.com. All rights reserved.
7 | //
8 |
9 | #if canImport(SwiftUI)
10 | import SwiftUI
11 | #endif
12 |
13 | @available(iOS 13.0.0, *)
14 | public struct MorphingText: UIViewRepresentable {
15 | public typealias UIViewType = LTMorphingLabel
16 |
17 | var text: String
18 | var morphingEffect: LTMorphingEffect
19 | var moprhingEnabled: Bool = true
20 | var font: UIFont
21 | var textColor: UIColor
22 | var textAlignment: NSTextAlignment
23 |
24 | public init(_ text: String,
25 | effect: LTMorphingEffect = .scale,
26 | font: UIFont = .systemFont(ofSize: 16),
27 | textColor: UIColor = .black,
28 | textAlignment: NSTextAlignment = .center
29 | ) {
30 | self.text = text
31 | self.morphingEffect = effect
32 | self.font = font
33 | self.textColor = textColor
34 | self.textAlignment = textAlignment
35 | }
36 |
37 | public func makeUIView(context: Context) -> UIViewType {
38 | let label = LTMorphingLabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
39 | label.textAlignment = .center
40 | label.textColor = UIColor.white
41 | return label
42 | }
43 |
44 | public func updateUIView(_ uiView: UIViewType, context: Context) {
45 | uiView.text = text
46 | uiView.font = font
47 | uiView.morphingEnabled = moprhingEnabled
48 | uiView.morphingEffect = morphingEffect
49 | uiView.textColor = textColor
50 | uiView.textAlignment = textAlignment
51 | }
52 | }
53 |
54 | @available(iOS 13.0.0, *)
55 | struct MorphingText_Previews: PreviewProvider {
56 |
57 | static var previews: some View {
58 | PreviewWrapper()
59 | .previewDevice("iPhone SE")
60 | .environment(\.colorScheme, .dark)
61 | }
62 |
63 | struct PreviewWrapper: View {
64 | @State var morphingEnabled = true
65 | @State var textIndex: Double = 0
66 | @State var effectIndex: Double = 0
67 |
68 | private var textArray = [
69 | "Supercalifragilisticexpialidocious",
70 | "Stay hungry, stay foolish.",
71 | "Love what you do and do what you love.",
72 | "Apple doesn't do hobbies as a general rule.",
73 | "iOS",
74 | "iPhone",
75 | "iPhone 11",
76 | "iPhone 11 Pro",
77 | "iPhone 11 Pro Max",
78 | "$9995.00",
79 | "$9996.00",
80 | "$9997.00",
81 | "$9998.00",
82 | "$9999.00",
83 | "$10000.00"
84 | ]
85 |
86 | public var body: some View {
87 | VStack {
88 | Spacer()
89 | Text("LTMorphingLabel").font(.largeTitle)
90 | Text("for SwiftUI").font(.title)
91 |
92 | MorphingText(
93 | textArray[Int(round(textIndex))],
94 | effect: LTMorphingEffect.allCases[Int(round(effectIndex))],
95 | font: UIFont.systemFont(ofSize: 20),
96 | textColor: .white
97 | )
98 | .frame(maxWidth: 200, maxHeight: 100)
99 |
100 | Text("Effect: \(LTMorphingEffect.allCases[Int(round(effectIndex))].description)").font(.title)
101 | Slider(value: $effectIndex, in: 0...Double(LTMorphingEffect.allCases.count - 1))
102 |
103 | Slider(value: $textIndex, in: 0...Double(textArray.count - 1))
104 |
105 | Toggle("MorphingEnabled", isOn: $morphingEnabled)
106 | Spacer()
107 | }
108 | .padding(20)
109 | .foregroundColor(Color.white)
110 | .background(Color.black)
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/LTMorphingLabel/tvOS-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D701040D2516F5E500DB98F7 /* MorphingText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D764373D2467A01A0037C36B /* MorphingText.swift */; platformFilter = maccatalyst; };
11 | D720D06B1A5E91CB00747465 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
12 | D720D06C1A5E91CB00747465 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
13 | D720D06D1A5E91CB00747465 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
14 | D720D06E1A5E91CB00747465 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
15 | D720D06F1A5E91CB00747465 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
16 | D720D0701A5E91CB00747465 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
17 | D720D0711A5E91CB00747465 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
18 | D720D0721A5E91CB00747465 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
19 | D720D0731A5E91CB00747465 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
20 | D720D0741A5E923100747465 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
21 | D720D0751A5E923100747465 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
22 | D720D0761A5E923100747465 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
23 | D720D0771A5E923100747465 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
24 | D720D0781A5E923100747465 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
25 | D720D0791A5E923100747465 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
26 | D720D07A1A5E923100747465 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
27 | D720D07B1A5E923100747465 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
28 | D720D07C1A5E923100747465 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
29 | D720D07D1A5E923800747465 /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
30 | D720D07E1A5E923800747465 /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
31 | D720D07F1A5E923800747465 /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
32 | D720D0801A5E923800747465 /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
33 | D72A94E01F7CAF8B007E5157 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
34 | D72A94E11F7CAFA5007E5157 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
35 | D73C19FA1AC2824100C1A824 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
36 | D73DFD021F4DB5CC00F84122 /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
37 | D73DFD031F4DB5CC00F84122 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
38 | D73DFD041F4DB5CC00F84122 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
39 | D73DFD051F4DB5CC00F84122 /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
40 | D73DFD061F4DB5CC00F84122 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
41 | D73DFD071F4DB5CC00F84122 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
42 | D73DFD081F4DB5CC00F84122 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
43 | D73DFD091F4DB5CC00F84122 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
44 | D73DFD0A1F4DB5CC00F84122 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
45 | D73DFD0B1F4DB5CC00F84122 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
46 | D73DFD0C1F4DB5CC00F84122 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
47 | D73DFD0D1F4DB5CC00F84122 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
48 | D73DFD0E1F4DB5CC00F84122 /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
49 | D73DFD111F4DB5CC00F84122 /* LTMorphingLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
50 | D73DFD131F4DB5CC00F84122 /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
51 | D73DFD141F4DB5CC00F84122 /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
52 | D73DFD151F4DB5CC00F84122 /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
53 | D73DFD161F4DB5CC00F84122 /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
54 | D73DFD231F5056A700F84122 /* LTMorphingLabelUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */; };
55 | D74AD974195171E7009A2ACD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD973195171E7009A2ACD /* AppDelegate.swift */; };
56 | D74AD976195171E7009A2ACD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D74AD975195171E7009A2ACD /* Images.xcassets */; };
57 | D74AD98D195173B5009A2ACD /* LTMorphingLabelDemo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */; };
58 | D7633A2B195812020009D084 /* LTDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2A195812020009D084 /* LTDemoViewController.swift */; };
59 | D7934DCB1A63AF1100AE04CE /* LTMorphingLabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */; };
60 | D797F6F91D2E992200531960 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
61 | D797F6FA1D2EA47A00531960 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
62 | D7D4B0241A5E87D50087F83D /* LTMorphingLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
63 | D7D4B0381A5E87D50087F83D /* MorphingLabel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
64 | D7D4B03F1A5E8F6E0087F83D /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
65 | D7D4B0401A5E8F6E0087F83D /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
66 | D7D4B0411A5E8F6E0087F83D /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
67 | D7D4B0421A5E8F6E0087F83D /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
68 | D7E537321B8CADF6008EF6D1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */; };
69 | D7EF4F041AB5608000D46A0E /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
70 | D7EF4F051AB5610200D46A0E /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
71 | D7EF4F071AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
72 | D7EF4F081AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
73 | D7EF4F0A1AB561A400D46A0E /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
74 | D7EF4F0B1AB561A400D46A0E /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
75 | /* End PBXBuildFile section */
76 |
77 | /* Begin PBXContainerItemProxy section */
78 | D72A94DD1F7CAF6D007E5157 /* PBXContainerItemProxy */ = {
79 | isa = PBXContainerItemProxy;
80 | containerPortal = D74AD966195171E7009A2ACD /* Project object */;
81 | proxyType = 1;
82 | remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
83 | remoteInfo = LTMorphingLabel;
84 | };
85 | D72A94E21F7CAFAA007E5157 /* PBXContainerItemProxy */ = {
86 | isa = PBXContainerItemProxy;
87 | containerPortal = D74AD966195171E7009A2ACD /* Project object */;
88 | proxyType = 1;
89 | remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
90 | remoteInfo = LTMorphingLabel;
91 | };
92 | D73C19F81AC2823900C1A824 /* PBXContainerItemProxy */ = {
93 | isa = PBXContainerItemProxy;
94 | containerPortal = D74AD966195171E7009A2ACD /* Project object */;
95 | proxyType = 1;
96 | remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
97 | remoteInfo = LTMorphingLabel;
98 | };
99 | D73C19FB1AC28DAA00C1A824 /* PBXContainerItemProxy */ = {
100 | isa = PBXContainerItemProxy;
101 | containerPortal = D74AD966195171E7009A2ACD /* Project object */;
102 | proxyType = 1;
103 | remoteGlobalIDString = D74AD96D195171E7009A2ACD;
104 | remoteInfo = LTMorphingLabelDemo;
105 | };
106 | D73DFD251F5056A700F84122 /* PBXContainerItemProxy */ = {
107 | isa = PBXContainerItemProxy;
108 | containerPortal = D74AD966195171E7009A2ACD /* Project object */;
109 | proxyType = 1;
110 | remoteGlobalIDString = D74AD96D195171E7009A2ACD;
111 | remoteInfo = LTMorphingLabelDemo;
112 | };
113 | /* End PBXContainerItemProxy section */
114 |
115 | /* Begin PBXCopyFilesBuildPhase section */
116 | D7D4B0371A5E87D50087F83D /* Embed Frameworks */ = {
117 | isa = PBXCopyFilesBuildPhase;
118 | buildActionMask = 2147483647;
119 | dstPath = "";
120 | dstSubfolderSpec = 10;
121 | files = (
122 | D7D4B0381A5E87D50087F83D /* MorphingLabel.framework in Embed Frameworks */,
123 | );
124 | name = "Embed Frameworks";
125 | runOnlyForDeploymentPostprocessing = 0;
126 | };
127 | /* End PBXCopyFilesBuildPhase section */
128 |
129 | /* Begin PBXFileReference section */
130 | D723B2CB196A3FD100B1BBE8 /* Sparkle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Sparkle.png; sourceTree = ""; };
131 | D72CE5F420863C9D005BBDEF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
132 | D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MorphingLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
133 | D73DFD1B1F4DB5CC00F84122 /* tvOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "tvOS-Info.plist"; path = "/Users/lex/git/LTMorphingLabel/LTMorphingLabel/tvOS-Info.plist"; sourceTree = ""; };
134 | D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LTMorphingLabelUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
135 | D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LTMorphingLabelUITests.swift; sourceTree = ""; };
136 | D73DFD241F5056A700F84122 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
137 | D74AD96E195171E7009A2ACD /* Morphing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Morphing.app; sourceTree = BUILT_PRODUCTS_DIR; };
138 | D74AD972195171E7009A2ACD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
139 | D74AD973195171E7009A2ACD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
140 | D74AD975195171E7009A2ACD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
141 | D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LTMorphingLabelDemo.storyboard; sourceTree = ""; };
142 | D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingLabel.swift; sourceTree = ""; };
143 | D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Pixelate.swift"; sourceTree = ""; };
144 | D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Burn.swift"; sourceTree = ""; };
145 | D757C31619742B1D00A34565 /* Fire.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fire.png; sourceTree = ""; };
146 | D7633A2A195812020009D084 /* LTDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTDemoViewController.swift; sourceTree = ""; };
147 | D7633A2C195965A00009D084 /* LTStringDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTStringDiffResult.swift; sourceTree = ""; };
148 | D764373D2467A01A0037C36B /* MorphingText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MorphingText.swift; sourceTree = ""; };
149 | D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LTMorphingLabelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
150 | D7934DC91A63AF1100AE04CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
151 | D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LTMorphingLabelTests.swift; sourceTree = ""; };
152 | D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterDiffResult.swift; sourceTree = ""; };
153 | D7AA544125170E1100299291 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
154 | D7AFEC911962511C0006FA88 /* LTEasing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEasing.swift; sourceTree = ""; };
155 | D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Evaporate.swift"; sourceTree = ""; };
156 | D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Fall.swift"; sourceTree = ""; };
157 | D7C98F3619750F6900902C5C /* Smoke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Smoke.png; sourceTree = ""; };
158 | D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Anvil.swift"; sourceTree = ""; };
159 | D7C98F3A1975298000902C5C /* Fragment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fragment.png; sourceTree = ""; };
160 | D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MorphingLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
161 | D7D4B0221A5E87D50087F83D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
162 | D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LTMorphingLabel.h; sourceTree = ""; };
163 | D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; };
164 | D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Sparkle.swift"; sourceTree = ""; };
165 | D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingEffect.swift; sourceTree = ""; };
166 | D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterLimbo.swift; sourceTree = ""; };
167 | D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEmitterView.swift; sourceTree = ""; };
168 | /* End PBXFileReference section */
169 |
170 | /* Begin PBXFrameworksBuildPhase section */
171 | D73DFD0F1F4DB5CC00F84122 /* Frameworks */ = {
172 | isa = PBXFrameworksBuildPhase;
173 | buildActionMask = 2147483647;
174 | files = (
175 | );
176 | runOnlyForDeploymentPostprocessing = 0;
177 | };
178 | D73DFD1D1F5056A700F84122 /* Frameworks */ = {
179 | isa = PBXFrameworksBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | D72A94E11F7CAFA5007E5157 /* MorphingLabel.framework in Frameworks */,
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | };
186 | D74AD96B195171E7009A2ACD /* Frameworks */ = {
187 | isa = PBXFrameworksBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | D72A94E01F7CAF8B007E5157 /* MorphingLabel.framework in Frameworks */,
191 | );
192 | runOnlyForDeploymentPostprocessing = 0;
193 | };
194 | D7934DC31A63AF1100AE04CE /* Frameworks */ = {
195 | isa = PBXFrameworksBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | D73C19FA1AC2824100C1A824 /* MorphingLabel.framework in Frameworks */,
199 | );
200 | runOnlyForDeploymentPostprocessing = 0;
201 | };
202 | D7D4B01B1A5E87D50087F83D /* Frameworks */ = {
203 | isa = PBXFrameworksBuildPhase;
204 | buildActionMask = 2147483647;
205 | files = (
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | /* End PBXFrameworksBuildPhase section */
210 |
211 | /* Begin PBXGroup section */
212 | D70FB1FB19685C3300EF9B84 /* Particles */ = {
213 | isa = PBXGroup;
214 | children = (
215 | D757C31619742B1D00A34565 /* Fire.png */,
216 | D723B2CB196A3FD100B1BBE8 /* Sparkle.png */,
217 | D7C98F3619750F6900902C5C /* Smoke.png */,
218 | D7C98F3A1975298000902C5C /* Fragment.png */,
219 | );
220 | path = Particles;
221 | sourceTree = "";
222 | };
223 | D72A94DF1F7CAF8B007E5157 /* Frameworks */ = {
224 | isa = PBXGroup;
225 | children = (
226 | );
227 | name = Frameworks;
228 | sourceTree = "";
229 | };
230 | D73DFD211F5056A700F84122 /* LTMorphingLabelUITests */ = {
231 | isa = PBXGroup;
232 | children = (
233 | D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */,
234 | D73DFD241F5056A700F84122 /* Info.plist */,
235 | );
236 | path = LTMorphingLabelUITests;
237 | sourceTree = "";
238 | };
239 | D74AD965195171E7009A2ACD = {
240 | isa = PBXGroup;
241 | children = (
242 | D7AA544125170E1100299291 /* Package.swift */,
243 | D72CE5F420863C9D005BBDEF /* README.md */,
244 | D74AD98B19517201009A2ACD /* LTMorphingLabel */,
245 | D74AD970195171E7009A2ACD /* LTMorphingLabelDemo */,
246 | D7D4B0201A5E87D50087F83D /* LTMorphingLabel */,
247 | D7934DC71A63AF1100AE04CE /* LTMorphingLabelTests */,
248 | D73DFD211F5056A700F84122 /* LTMorphingLabelUITests */,
249 | D74AD96F195171E7009A2ACD /* Products */,
250 | D72A94DF1F7CAF8B007E5157 /* Frameworks */,
251 | );
252 | sourceTree = "";
253 | };
254 | D74AD96F195171E7009A2ACD /* Products */ = {
255 | isa = PBXGroup;
256 | children = (
257 | D74AD96E195171E7009A2ACD /* Morphing.app */,
258 | D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */,
259 | D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */,
260 | D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */,
261 | D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */,
262 | );
263 | name = Products;
264 | sourceTree = "";
265 | };
266 | D74AD970195171E7009A2ACD /* LTMorphingLabelDemo */ = {
267 | isa = PBXGroup;
268 | children = (
269 | D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */,
270 | D74AD973195171E7009A2ACD /* AppDelegate.swift */,
271 | D74AD975195171E7009A2ACD /* Images.xcassets */,
272 | D74AD971195171E7009A2ACD /* Supporting Files */,
273 | D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */,
274 | D7633A2A195812020009D084 /* LTDemoViewController.swift */,
275 | );
276 | path = LTMorphingLabelDemo;
277 | sourceTree = "";
278 | };
279 | D74AD971195171E7009A2ACD /* Supporting Files */ = {
280 | isa = PBXGroup;
281 | children = (
282 | D74AD972195171E7009A2ACD /* Info.plist */,
283 | );
284 | name = "Supporting Files";
285 | sourceTree = "";
286 | };
287 | D74AD98B19517201009A2ACD /* LTMorphingLabel */ = {
288 | isa = PBXGroup;
289 | children = (
290 | D7AFEC911962511C0006FA88 /* LTEasing.swift */,
291 | D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */,
292 | D7633A2C195965A00009D084 /* LTStringDiffResult.swift */,
293 | D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */,
294 | D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */,
295 | D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */,
296 | D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */,
297 | D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */,
298 | D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */,
299 | D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */,
300 | D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */,
301 | D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */,
302 | D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */,
303 | D70FB1FB19685C3300EF9B84 /* Particles */,
304 | D7868570246848E100D4C46F /* SwiftUI */,
305 | );
306 | path = LTMorphingLabel;
307 | sourceTree = "";
308 | };
309 | D7868570246848E100D4C46F /* SwiftUI */ = {
310 | isa = PBXGroup;
311 | children = (
312 | D764373D2467A01A0037C36B /* MorphingText.swift */,
313 | );
314 | path = SwiftUI;
315 | sourceTree = "";
316 | };
317 | D7934DC71A63AF1100AE04CE /* LTMorphingLabelTests */ = {
318 | isa = PBXGroup;
319 | children = (
320 | D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */,
321 | D7934DC81A63AF1100AE04CE /* Supporting Files */,
322 | );
323 | path = LTMorphingLabelTests;
324 | sourceTree = "";
325 | };
326 | D7934DC81A63AF1100AE04CE /* Supporting Files */ = {
327 | isa = PBXGroup;
328 | children = (
329 | D7934DC91A63AF1100AE04CE /* Info.plist */,
330 | );
331 | name = "Supporting Files";
332 | sourceTree = "";
333 | };
334 | D7D4B0201A5E87D50087F83D /* LTMorphingLabel */ = {
335 | isa = PBXGroup;
336 | children = (
337 | D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */,
338 | D7D4B0211A5E87D50087F83D /* Supporting Files */,
339 | );
340 | path = LTMorphingLabel;
341 | sourceTree = "";
342 | };
343 | D7D4B0211A5E87D50087F83D /* Supporting Files */ = {
344 | isa = PBXGroup;
345 | children = (
346 | D7D4B0221A5E87D50087F83D /* Info.plist */,
347 | D73DFD1B1F4DB5CC00F84122 /* tvOS-Info.plist */,
348 | );
349 | name = "Supporting Files";
350 | sourceTree = "";
351 | };
352 | /* End PBXGroup section */
353 |
354 | /* Begin PBXHeadersBuildPhase section */
355 | D73DFD101F4DB5CC00F84122 /* Headers */ = {
356 | isa = PBXHeadersBuildPhase;
357 | buildActionMask = 2147483647;
358 | files = (
359 | D73DFD111F4DB5CC00F84122 /* LTMorphingLabel.h in Headers */,
360 | );
361 | runOnlyForDeploymentPostprocessing = 0;
362 | };
363 | D7D4B01C1A5E87D50087F83D /* Headers */ = {
364 | isa = PBXHeadersBuildPhase;
365 | buildActionMask = 2147483647;
366 | files = (
367 | D7D4B0241A5E87D50087F83D /* LTMorphingLabel.h in Headers */,
368 | );
369 | runOnlyForDeploymentPostprocessing = 0;
370 | };
371 | /* End PBXHeadersBuildPhase section */
372 |
373 | /* Begin PBXNativeTarget section */
374 | D73DFD001F4DB5CC00F84122 /* MorphingLabel_tvOS */ = {
375 | isa = PBXNativeTarget;
376 | buildConfigurationList = D73DFD171F4DB5CC00F84122 /* Build configuration list for PBXNativeTarget "MorphingLabel_tvOS" */;
377 | buildPhases = (
378 | D73DFD011F4DB5CC00F84122 /* Sources */,
379 | D73DFD0F1F4DB5CC00F84122 /* Frameworks */,
380 | D73DFD101F4DB5CC00F84122 /* Headers */,
381 | D73DFD121F4DB5CC00F84122 /* Resources */,
382 | );
383 | buildRules = (
384 | );
385 | dependencies = (
386 | );
387 | name = MorphingLabel_tvOS;
388 | productName = LTMorphingLabel;
389 | productReference = D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */;
390 | productType = "com.apple.product-type.framework";
391 | };
392 | D73DFD1F1F5056A700F84122 /* LTMorphingLabelUITests */ = {
393 | isa = PBXNativeTarget;
394 | buildConfigurationList = D73DFD291F5056A700F84122 /* Build configuration list for PBXNativeTarget "LTMorphingLabelUITests" */;
395 | buildPhases = (
396 | D73DFD1C1F5056A700F84122 /* Sources */,
397 | D73DFD1D1F5056A700F84122 /* Frameworks */,
398 | D73DFD1E1F5056A700F84122 /* Resources */,
399 | );
400 | buildRules = (
401 | );
402 | dependencies = (
403 | D73DFD261F5056A700F84122 /* PBXTargetDependency */,
404 | D72A94E31F7CAFAA007E5157 /* PBXTargetDependency */,
405 | );
406 | name = LTMorphingLabelUITests;
407 | productName = LTMorphingLabelUITests;
408 | productReference = D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */;
409 | productType = "com.apple.product-type.bundle.ui-testing";
410 | };
411 | D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */ = {
412 | isa = PBXNativeTarget;
413 | buildConfigurationList = D74AD985195171E7009A2ACD /* Build configuration list for PBXNativeTarget "LTMorphingLabelDemo" */;
414 | buildPhases = (
415 | D74AD96A195171E7009A2ACD /* Sources */,
416 | D74AD96B195171E7009A2ACD /* Frameworks */,
417 | D74AD96C195171E7009A2ACD /* Resources */,
418 | D7D4B0371A5E87D50087F83D /* Embed Frameworks */,
419 | D7E30A621C28449F00A708CF /* SwiftLint */,
420 | );
421 | buildRules = (
422 | );
423 | dependencies = (
424 | D72A94DE1F7CAF6D007E5157 /* PBXTargetDependency */,
425 | );
426 | name = LTMorphingLabelDemo;
427 | productName = LTMorphingLabelDemo;
428 | productReference = D74AD96E195171E7009A2ACD /* Morphing.app */;
429 | productType = "com.apple.product-type.application";
430 | };
431 | D7934DC51A63AF1100AE04CE /* LTMorphingLabelTests */ = {
432 | isa = PBXNativeTarget;
433 | buildConfigurationList = D7934DD11A63AF1100AE04CE /* Build configuration list for PBXNativeTarget "LTMorphingLabelTests" */;
434 | buildPhases = (
435 | D7934DC21A63AF1100AE04CE /* Sources */,
436 | D7934DC31A63AF1100AE04CE /* Frameworks */,
437 | D7934DC41A63AF1100AE04CE /* Resources */,
438 | );
439 | buildRules = (
440 | );
441 | dependencies = (
442 | D73C19F91AC2823900C1A824 /* PBXTargetDependency */,
443 | D73C19FC1AC28DAA00C1A824 /* PBXTargetDependency */,
444 | );
445 | name = LTMorphingLabelTests;
446 | productName = LTMorphingLabelTests;
447 | productReference = D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */;
448 | productType = "com.apple.product-type.bundle.unit-test";
449 | };
450 | D7D4B01E1A5E87D50087F83D /* MorphingLabel */ = {
451 | isa = PBXNativeTarget;
452 | buildConfigurationList = D7D4B03D1A5E87D50087F83D /* Build configuration list for PBXNativeTarget "MorphingLabel" */;
453 | buildPhases = (
454 | D7D4B01A1A5E87D50087F83D /* Sources */,
455 | D7D4B01B1A5E87D50087F83D /* Frameworks */,
456 | D7D4B01C1A5E87D50087F83D /* Headers */,
457 | D7D4B01D1A5E87D50087F83D /* Resources */,
458 | );
459 | buildRules = (
460 | );
461 | dependencies = (
462 | );
463 | name = MorphingLabel;
464 | productName = LTMorphingLabel;
465 | productReference = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */;
466 | productType = "com.apple.product-type.framework";
467 | };
468 | /* End PBXNativeTarget section */
469 |
470 | /* Begin PBXProject section */
471 | D74AD966195171E7009A2ACD /* Project object */ = {
472 | isa = PBXProject;
473 | attributes = {
474 | LastSwiftMigration = 0700;
475 | LastSwiftUpdateCheck = 0830;
476 | LastUpgradeCheck = 1240;
477 | ORGANIZATIONNAME = lexrus.com;
478 | TargetAttributes = {
479 | D73DFD1F1F5056A700F84122 = {
480 | CreatedOnToolsVersion = 8.3.3;
481 | DevelopmentTeam = 5SKD83S59G;
482 | LastSwiftMigration = 1020;
483 | ProvisioningStyle = Automatic;
484 | TestTargetID = D74AD96D195171E7009A2ACD;
485 | };
486 | D74AD96D195171E7009A2ACD = {
487 | CreatedOnToolsVersion = 6.0;
488 | LastSwiftMigration = 1020;
489 | };
490 | D7934DC51A63AF1100AE04CE = {
491 | CreatedOnToolsVersion = 6.1.1;
492 | LastSwiftMigration = 1020;
493 | TestTargetID = D74AD96D195171E7009A2ACD;
494 | };
495 | D7D4B01E1A5E87D50087F83D = {
496 | CreatedOnToolsVersion = 6.1.1;
497 | LastSwiftMigration = 1020;
498 | };
499 | };
500 | };
501 | buildConfigurationList = D74AD969195171E7009A2ACD /* Build configuration list for PBXProject "LTMorphingLabelDemo" */;
502 | compatibilityVersion = "Xcode 6.3";
503 | developmentRegion = en;
504 | hasScannedForEncodings = 0;
505 | knownRegions = (
506 | en,
507 | Base,
508 | );
509 | mainGroup = D74AD965195171E7009A2ACD;
510 | productRefGroup = D74AD96F195171E7009A2ACD /* Products */;
511 | projectDirPath = "";
512 | projectRoot = "";
513 | targets = (
514 | D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */,
515 | D7D4B01E1A5E87D50087F83D /* MorphingLabel */,
516 | D7934DC51A63AF1100AE04CE /* LTMorphingLabelTests */,
517 | D73DFD001F4DB5CC00F84122 /* MorphingLabel_tvOS */,
518 | D73DFD1F1F5056A700F84122 /* LTMorphingLabelUITests */,
519 | );
520 | };
521 | /* End PBXProject section */
522 |
523 | /* Begin PBXResourcesBuildPhase section */
524 | D73DFD121F4DB5CC00F84122 /* Resources */ = {
525 | isa = PBXResourcesBuildPhase;
526 | buildActionMask = 2147483647;
527 | files = (
528 | D73DFD131F4DB5CC00F84122 /* Fire.png in Resources */,
529 | D73DFD141F4DB5CC00F84122 /* Sparkle.png in Resources */,
530 | D73DFD151F4DB5CC00F84122 /* Smoke.png in Resources */,
531 | D73DFD161F4DB5CC00F84122 /* Fragment.png in Resources */,
532 | );
533 | runOnlyForDeploymentPostprocessing = 0;
534 | };
535 | D73DFD1E1F5056A700F84122 /* Resources */ = {
536 | isa = PBXResourcesBuildPhase;
537 | buildActionMask = 2147483647;
538 | files = (
539 | );
540 | runOnlyForDeploymentPostprocessing = 0;
541 | };
542 | D74AD96C195171E7009A2ACD /* Resources */ = {
543 | isa = PBXResourcesBuildPhase;
544 | buildActionMask = 2147483647;
545 | files = (
546 | D720D07D1A5E923800747465 /* Fire.png in Resources */,
547 | D720D07E1A5E923800747465 /* Sparkle.png in Resources */,
548 | D720D07F1A5E923800747465 /* Smoke.png in Resources */,
549 | D720D0801A5E923800747465 /* Fragment.png in Resources */,
550 | D74AD98D195173B5009A2ACD /* LTMorphingLabelDemo.storyboard in Resources */,
551 | D74AD976195171E7009A2ACD /* Images.xcassets in Resources */,
552 | D7E537321B8CADF6008EF6D1 /* Launch Screen.storyboard in Resources */,
553 | );
554 | runOnlyForDeploymentPostprocessing = 0;
555 | };
556 | D7934DC41A63AF1100AE04CE /* Resources */ = {
557 | isa = PBXResourcesBuildPhase;
558 | buildActionMask = 2147483647;
559 | files = (
560 | );
561 | runOnlyForDeploymentPostprocessing = 0;
562 | };
563 | D7D4B01D1A5E87D50087F83D /* Resources */ = {
564 | isa = PBXResourcesBuildPhase;
565 | buildActionMask = 2147483647;
566 | files = (
567 | D7D4B03F1A5E8F6E0087F83D /* Fire.png in Resources */,
568 | D7D4B0401A5E8F6E0087F83D /* Sparkle.png in Resources */,
569 | D7D4B0411A5E8F6E0087F83D /* Smoke.png in Resources */,
570 | D7D4B0421A5E8F6E0087F83D /* Fragment.png in Resources */,
571 | );
572 | runOnlyForDeploymentPostprocessing = 0;
573 | };
574 | /* End PBXResourcesBuildPhase section */
575 |
576 | /* Begin PBXShellScriptBuildPhase section */
577 | D7E30A621C28449F00A708CF /* SwiftLint */ = {
578 | isa = PBXShellScriptBuildPhase;
579 | buildActionMask = 2147483647;
580 | files = (
581 | );
582 | inputPaths = (
583 | );
584 | name = SwiftLint;
585 | outputPaths = (
586 | );
587 | runOnlyForDeploymentPostprocessing = 0;
588 | shellPath = /bin/sh;
589 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"SwiftLint does not exist, download from https://github.com/realm/SwiftLint\"\nfi\n";
590 | };
591 | /* End PBXShellScriptBuildPhase section */
592 |
593 | /* Begin PBXSourcesBuildPhase section */
594 | D73DFD011F4DB5CC00F84122 /* Sources */ = {
595 | isa = PBXSourcesBuildPhase;
596 | buildActionMask = 2147483647;
597 | files = (
598 | D73DFD021F4DB5CC00F84122 /* LTCharacterLimbo.swift in Sources */,
599 | D73DFD031F4DB5CC00F84122 /* LTEasing.swift in Sources */,
600 | D73DFD041F4DB5CC00F84122 /* LTStringDiffResult.swift in Sources */,
601 | D73DFD051F4DB5CC00F84122 /* LTMorphingEffect.swift in Sources */,
602 | D73DFD061F4DB5CC00F84122 /* LTMorphingLabel.swift in Sources */,
603 | D73DFD071F4DB5CC00F84122 /* LTCharacterDiffResult.swift in Sources */,
604 | D73DFD081F4DB5CC00F84122 /* LTMorphingLabel+Evaporate.swift in Sources */,
605 | D73DFD091F4DB5CC00F84122 /* LTMorphingLabel+Fall.swift in Sources */,
606 | D73DFD0A1F4DB5CC00F84122 /* LTMorphingLabel+Pixelate.swift in Sources */,
607 | D73DFD0B1F4DB5CC00F84122 /* LTMorphingLabel+Sparkle.swift in Sources */,
608 | D73DFD0C1F4DB5CC00F84122 /* LTMorphingLabel+Burn.swift in Sources */,
609 | D73DFD0D1F4DB5CC00F84122 /* LTMorphingLabel+Anvil.swift in Sources */,
610 | D73DFD0E1F4DB5CC00F84122 /* LTEmitterView.swift in Sources */,
611 | );
612 | runOnlyForDeploymentPostprocessing = 0;
613 | };
614 | D73DFD1C1F5056A700F84122 /* Sources */ = {
615 | isa = PBXSourcesBuildPhase;
616 | buildActionMask = 2147483647;
617 | files = (
618 | D73DFD231F5056A700F84122 /* LTMorphingLabelUITests.swift in Sources */,
619 | );
620 | runOnlyForDeploymentPostprocessing = 0;
621 | };
622 | D74AD96A195171E7009A2ACD /* Sources */ = {
623 | isa = PBXSourcesBuildPhase;
624 | buildActionMask = 2147483647;
625 | files = (
626 | D720D0741A5E923100747465 /* LTEasing.swift in Sources */,
627 | D7EF4F071AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */,
628 | D720D0751A5E923100747465 /* LTStringDiffResult.swift in Sources */,
629 | D7EF4F051AB5610200D46A0E /* LTMorphingEffect.swift in Sources */,
630 | D720D0761A5E923100747465 /* LTMorphingLabel.swift in Sources */,
631 | D720D0771A5E923100747465 /* LTMorphingLabel+Evaporate.swift in Sources */,
632 | D720D0781A5E923100747465 /* LTMorphingLabel+Fall.swift in Sources */,
633 | D720D0791A5E923100747465 /* LTMorphingLabel+Pixelate.swift in Sources */,
634 | D720D07A1A5E923100747465 /* LTMorphingLabel+Sparkle.swift in Sources */,
635 | D720D07B1A5E923100747465 /* LTMorphingLabel+Burn.swift in Sources */,
636 | D720D07C1A5E923100747465 /* LTMorphingLabel+Anvil.swift in Sources */,
637 | D7EF4F0A1AB561A400D46A0E /* LTEmitterView.swift in Sources */,
638 | D74AD974195171E7009A2ACD /* AppDelegate.swift in Sources */,
639 | D797F6FA1D2EA47A00531960 /* LTCharacterDiffResult.swift in Sources */,
640 | D7633A2B195812020009D084 /* LTDemoViewController.swift in Sources */,
641 | );
642 | runOnlyForDeploymentPostprocessing = 0;
643 | };
644 | D7934DC21A63AF1100AE04CE /* Sources */ = {
645 | isa = PBXSourcesBuildPhase;
646 | buildActionMask = 2147483647;
647 | files = (
648 | D7934DCB1A63AF1100AE04CE /* LTMorphingLabelTests.swift in Sources */,
649 | );
650 | runOnlyForDeploymentPostprocessing = 0;
651 | };
652 | D7D4B01A1A5E87D50087F83D /* Sources */ = {
653 | isa = PBXSourcesBuildPhase;
654 | buildActionMask = 2147483647;
655 | files = (
656 | D701040D2516F5E500DB98F7 /* MorphingText.swift in Sources */,
657 | D7EF4F081AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */,
658 | D720D06B1A5E91CB00747465 /* LTEasing.swift in Sources */,
659 | D720D06C1A5E91CB00747465 /* LTStringDiffResult.swift in Sources */,
660 | D7EF4F041AB5608000D46A0E /* LTMorphingEffect.swift in Sources */,
661 | D720D06D1A5E91CB00747465 /* LTMorphingLabel.swift in Sources */,
662 | D797F6F91D2E992200531960 /* LTCharacterDiffResult.swift in Sources */,
663 | D720D06E1A5E91CB00747465 /* LTMorphingLabel+Evaporate.swift in Sources */,
664 | D720D06F1A5E91CB00747465 /* LTMorphingLabel+Fall.swift in Sources */,
665 | D720D0701A5E91CB00747465 /* LTMorphingLabel+Pixelate.swift in Sources */,
666 | D720D0711A5E91CB00747465 /* LTMorphingLabel+Sparkle.swift in Sources */,
667 | D720D0721A5E91CB00747465 /* LTMorphingLabel+Burn.swift in Sources */,
668 | D720D0731A5E91CB00747465 /* LTMorphingLabel+Anvil.swift in Sources */,
669 | D7EF4F0B1AB561A400D46A0E /* LTEmitterView.swift in Sources */,
670 | );
671 | runOnlyForDeploymentPostprocessing = 0;
672 | };
673 | /* End PBXSourcesBuildPhase section */
674 |
675 | /* Begin PBXTargetDependency section */
676 | D72A94DE1F7CAF6D007E5157 /* PBXTargetDependency */ = {
677 | isa = PBXTargetDependency;
678 | target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
679 | targetProxy = D72A94DD1F7CAF6D007E5157 /* PBXContainerItemProxy */;
680 | };
681 | D72A94E31F7CAFAA007E5157 /* PBXTargetDependency */ = {
682 | isa = PBXTargetDependency;
683 | target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
684 | targetProxy = D72A94E21F7CAFAA007E5157 /* PBXContainerItemProxy */;
685 | };
686 | D73C19F91AC2823900C1A824 /* PBXTargetDependency */ = {
687 | isa = PBXTargetDependency;
688 | target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
689 | targetProxy = D73C19F81AC2823900C1A824 /* PBXContainerItemProxy */;
690 | };
691 | D73C19FC1AC28DAA00C1A824 /* PBXTargetDependency */ = {
692 | isa = PBXTargetDependency;
693 | target = D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */;
694 | targetProxy = D73C19FB1AC28DAA00C1A824 /* PBXContainerItemProxy */;
695 | };
696 | D73DFD261F5056A700F84122 /* PBXTargetDependency */ = {
697 | isa = PBXTargetDependency;
698 | target = D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */;
699 | targetProxy = D73DFD251F5056A700F84122 /* PBXContainerItemProxy */;
700 | };
701 | /* End PBXTargetDependency section */
702 |
703 | /* Begin XCBuildConfiguration section */
704 | D73DFD181F4DB5CC00F84122 /* Debug */ = {
705 | isa = XCBuildConfiguration;
706 | buildSettings = {
707 | APPLICATION_EXTENSION_API_ONLY = YES;
708 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
709 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
710 | CURRENT_PROJECT_VERSION = 1;
711 | DEFINES_MODULE = YES;
712 | DYLIB_COMPATIBILITY_VERSION = 1;
713 | DYLIB_CURRENT_VERSION = 1;
714 | DYLIB_INSTALL_NAME_BASE = "@rpath";
715 | GCC_PREPROCESSOR_DEFINITIONS = (
716 | "DEBUG=1",
717 | "$(inherited)",
718 | );
719 | INFOPLIST_FILE = "$(SRCROOT)/LTMorphingLabel/tvOS-Info.plist";
720 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
721 | LD_RUNPATH_SEARCH_PATHS = (
722 | "$(inherited)",
723 | "@executable_path/Frameworks",
724 | "@loader_path/Frameworks",
725 | );
726 | MTL_ENABLE_DEBUG_INFO = YES;
727 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
728 | PRODUCT_NAME = MorphingLabel;
729 | SDKROOT = appletvos;
730 | SKIP_INSTALL = YES;
731 | TARGETED_DEVICE_FAMILY = "1,2,3";
732 | TVOS_DEPLOYMENT_TARGET = 12.0;
733 | VERSIONING_SYSTEM = "apple-generic";
734 | VERSION_INFO_PREFIX = "";
735 | };
736 | name = Debug;
737 | };
738 | D73DFD191F4DB5CC00F84122 /* Release */ = {
739 | isa = XCBuildConfiguration;
740 | buildSettings = {
741 | APPLICATION_EXTENSION_API_ONLY = YES;
742 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
743 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
744 | CURRENT_PROJECT_VERSION = 1;
745 | DEFINES_MODULE = YES;
746 | DYLIB_COMPATIBILITY_VERSION = 1;
747 | DYLIB_CURRENT_VERSION = 1;
748 | DYLIB_INSTALL_NAME_BASE = "@rpath";
749 | INFOPLIST_FILE = "$(SRCROOT)/LTMorphingLabel/tvOS-Info.plist";
750 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
751 | LD_RUNPATH_SEARCH_PATHS = (
752 | "$(inherited)",
753 | "@executable_path/Frameworks",
754 | "@loader_path/Frameworks",
755 | );
756 | MTL_ENABLE_DEBUG_INFO = NO;
757 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
758 | PRODUCT_NAME = MorphingLabel;
759 | SDKROOT = appletvos;
760 | SKIP_INSTALL = YES;
761 | TARGETED_DEVICE_FAMILY = "1,2,3";
762 | TVOS_DEPLOYMENT_TARGET = 12.0;
763 | VERSIONING_SYSTEM = "apple-generic";
764 | VERSION_INFO_PREFIX = "";
765 | };
766 | name = Release;
767 | };
768 | D73DFD271F5056A700F84122 /* Debug */ = {
769 | isa = XCBuildConfiguration;
770 | buildSettings = {
771 | CLANG_ANALYZER_NONNULL = YES;
772 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
773 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
774 | DEBUG_INFORMATION_FORMAT = dwarf;
775 | DEVELOPMENT_TEAM = 5SKD83S59G;
776 | INFOPLIST_FILE = LTMorphingLabelUITests/Info.plist;
777 | LD_RUNPATH_SEARCH_PATHS = (
778 | "$(inherited)",
779 | "@executable_path/Frameworks",
780 | "@loader_path/Frameworks",
781 | );
782 | MTL_ENABLE_DEBUG_INFO = YES;
783 | PRODUCT_BUNDLE_IDENTIFIER = com.LexTang.LTMorphingLabelUITests;
784 | PRODUCT_NAME = "$(TARGET_NAME)";
785 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
786 | TEST_TARGET_NAME = LTMorphingLabelDemo;
787 | };
788 | name = Debug;
789 | };
790 | D73DFD281F5056A700F84122 /* Release */ = {
791 | isa = XCBuildConfiguration;
792 | buildSettings = {
793 | CLANG_ANALYZER_NONNULL = YES;
794 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
795 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
796 | COPY_PHASE_STRIP = NO;
797 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
798 | DEVELOPMENT_TEAM = 5SKD83S59G;
799 | INFOPLIST_FILE = LTMorphingLabelUITests/Info.plist;
800 | LD_RUNPATH_SEARCH_PATHS = (
801 | "$(inherited)",
802 | "@executable_path/Frameworks",
803 | "@loader_path/Frameworks",
804 | );
805 | MTL_ENABLE_DEBUG_INFO = NO;
806 | PRODUCT_BUNDLE_IDENTIFIER = com.LexTang.LTMorphingLabelUITests;
807 | PRODUCT_NAME = "$(TARGET_NAME)";
808 | TEST_TARGET_NAME = LTMorphingLabelDemo;
809 | };
810 | name = Release;
811 | };
812 | D74AD983195171E7009A2ACD /* Debug */ = {
813 | isa = XCBuildConfiguration;
814 | buildSettings = {
815 | ALWAYS_SEARCH_USER_PATHS = NO;
816 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
817 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
818 | CLANG_CXX_LIBRARY = "libc++";
819 | CLANG_ENABLE_MODULES = YES;
820 | CLANG_ENABLE_OBJC_ARC = YES;
821 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
822 | CLANG_WARN_BOOL_CONVERSION = YES;
823 | CLANG_WARN_COMMA = YES;
824 | CLANG_WARN_CONSTANT_CONVERSION = YES;
825 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
826 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
827 | CLANG_WARN_EMPTY_BODY = YES;
828 | CLANG_WARN_ENUM_CONVERSION = YES;
829 | CLANG_WARN_INFINITE_RECURSION = YES;
830 | CLANG_WARN_INT_CONVERSION = YES;
831 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
832 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
833 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
834 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
835 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
836 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
837 | CLANG_WARN_STRICT_PROTOTYPES = YES;
838 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
839 | CLANG_WARN_UNREACHABLE_CODE = YES;
840 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
841 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
842 | COPY_PHASE_STRIP = NO;
843 | ENABLE_STRICT_OBJC_MSGSEND = YES;
844 | ENABLE_TESTABILITY = YES;
845 | GCC_C_LANGUAGE_STANDARD = gnu99;
846 | GCC_DYNAMIC_NO_PIC = NO;
847 | GCC_NO_COMMON_BLOCKS = YES;
848 | GCC_OPTIMIZATION_LEVEL = 0;
849 | GCC_PREPROCESSOR_DEFINITIONS = (
850 | "DEBUG=1",
851 | "$(inherited)",
852 | );
853 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
854 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
855 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
856 | GCC_WARN_UNDECLARED_SELECTOR = YES;
857 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
858 | GCC_WARN_UNUSED_FUNCTION = YES;
859 | GCC_WARN_UNUSED_VARIABLE = YES;
860 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
861 | METAL_ENABLE_DEBUG_INFO = YES;
862 | ONLY_ACTIVE_ARCH = YES;
863 | SDKROOT = iphoneos;
864 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
865 | SWIFT_VERSION = 5.0;
866 | };
867 | name = Debug;
868 | };
869 | D74AD984195171E7009A2ACD /* Release */ = {
870 | isa = XCBuildConfiguration;
871 | buildSettings = {
872 | ALWAYS_SEARCH_USER_PATHS = NO;
873 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
874 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
875 | CLANG_CXX_LIBRARY = "libc++";
876 | CLANG_ENABLE_MODULES = YES;
877 | CLANG_ENABLE_OBJC_ARC = YES;
878 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
879 | CLANG_WARN_BOOL_CONVERSION = YES;
880 | CLANG_WARN_COMMA = YES;
881 | CLANG_WARN_CONSTANT_CONVERSION = YES;
882 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
883 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
884 | CLANG_WARN_EMPTY_BODY = YES;
885 | CLANG_WARN_ENUM_CONVERSION = YES;
886 | CLANG_WARN_INFINITE_RECURSION = YES;
887 | CLANG_WARN_INT_CONVERSION = YES;
888 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
889 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
890 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
891 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
892 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
893 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
894 | CLANG_WARN_STRICT_PROTOTYPES = YES;
895 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
896 | CLANG_WARN_UNREACHABLE_CODE = YES;
897 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
898 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
899 | COPY_PHASE_STRIP = YES;
900 | ENABLE_NS_ASSERTIONS = NO;
901 | ENABLE_STRICT_OBJC_MSGSEND = YES;
902 | GCC_C_LANGUAGE_STANDARD = gnu99;
903 | GCC_NO_COMMON_BLOCKS = YES;
904 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
905 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
906 | GCC_WARN_UNDECLARED_SELECTOR = YES;
907 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
908 | GCC_WARN_UNUSED_FUNCTION = YES;
909 | GCC_WARN_UNUSED_VARIABLE = YES;
910 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
911 | METAL_ENABLE_DEBUG_INFO = NO;
912 | SDKROOT = iphoneos;
913 | SWIFT_COMPILATION_MODE = wholemodule;
914 | SWIFT_OPTIMIZATION_LEVEL = "-O";
915 | SWIFT_VERSION = 5.0;
916 | VALIDATE_PRODUCT = YES;
917 | };
918 | name = Release;
919 | };
920 | D74AD986195171E7009A2ACD /* Debug */ = {
921 | isa = XCBuildConfiguration;
922 | buildSettings = {
923 | ALWAYS_SEARCH_USER_PATHS = NO;
924 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
925 | CLANG_ENABLE_MODULES = YES;
926 | CODE_SIGN_IDENTITY = "iPhone Developer";
927 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
928 | DEVELOPMENT_TEAM = 5SKD83S59G;
929 | INFOPLIST_FILE = LTMorphingLabelDemo/Info.plist;
930 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
931 | LD_RUNPATH_SEARCH_PATHS = (
932 | "$(inherited)",
933 | "@executable_path/Frameworks",
934 | );
935 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabelDemo;
936 | PRODUCT_NAME = Morphing;
937 | PROVISIONING_PROFILE = "";
938 | SWIFT_INCLUDE_PATHS = "";
939 | SWIFT_OBJC_BRIDGING_HEADER = "";
940 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
941 | TARGETED_DEVICE_FAMILY = "1,2";
942 | };
943 | name = Debug;
944 | };
945 | D74AD987195171E7009A2ACD /* Release */ = {
946 | isa = XCBuildConfiguration;
947 | buildSettings = {
948 | ALWAYS_SEARCH_USER_PATHS = NO;
949 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
950 | CLANG_ENABLE_MODULES = YES;
951 | CODE_SIGN_IDENTITY = "iPhone Developer";
952 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
953 | DEVELOPMENT_TEAM = 5SKD83S59G;
954 | INFOPLIST_FILE = LTMorphingLabelDemo/Info.plist;
955 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
956 | LD_RUNPATH_SEARCH_PATHS = (
957 | "$(inherited)",
958 | "@executable_path/Frameworks",
959 | );
960 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabelDemo;
961 | PRODUCT_NAME = Morphing;
962 | PROVISIONING_PROFILE = "";
963 | SWIFT_INCLUDE_PATHS = "";
964 | SWIFT_OBJC_BRIDGING_HEADER = "";
965 | TARGETED_DEVICE_FAMILY = "1,2";
966 | };
967 | name = Release;
968 | };
969 | D7934DCF1A63AF1100AE04CE /* Debug */ = {
970 | isa = XCBuildConfiguration;
971 | buildSettings = {
972 | GCC_PREPROCESSOR_DEFINITIONS = (
973 | "DEBUG=1",
974 | "$(inherited)",
975 | );
976 | INFOPLIST_FILE = LTMorphingLabelTests/Info.plist;
977 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
978 | MTL_ENABLE_DEBUG_INFO = YES;
979 | PRODUCT_BUNDLE_IDENTIFIER = "com.LexTang.$(PRODUCT_NAME:rfc1034identifier)";
980 | PRODUCT_NAME = "$(TARGET_NAME)";
981 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LTMorphingLabelDemo.app/LTMorphingLabelDemo";
982 | };
983 | name = Debug;
984 | };
985 | D7934DD01A63AF1100AE04CE /* Release */ = {
986 | isa = XCBuildConfiguration;
987 | buildSettings = {
988 | INFOPLIST_FILE = LTMorphingLabelTests/Info.plist;
989 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
990 | MTL_ENABLE_DEBUG_INFO = NO;
991 | PRODUCT_BUNDLE_IDENTIFIER = "com.LexTang.$(PRODUCT_NAME:rfc1034identifier)";
992 | PRODUCT_NAME = "$(TARGET_NAME)";
993 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LTMorphingLabelDemo.app/LTMorphingLabelDemo";
994 | };
995 | name = Release;
996 | };
997 | D7D4B0391A5E87D50087F83D /* Debug */ = {
998 | isa = XCBuildConfiguration;
999 | buildSettings = {
1000 | APPLICATION_EXTENSION_API_ONLY = YES;
1001 | CODE_SIGN_IDENTITY = "";
1002 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
1003 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
1004 | CODE_SIGN_STYLE = Manual;
1005 | CURRENT_PROJECT_VERSION = 1;
1006 | DEFINES_MODULE = YES;
1007 | DEVELOPMENT_TEAM = "";
1008 | DYLIB_COMPATIBILITY_VERSION = 1;
1009 | DYLIB_CURRENT_VERSION = 1;
1010 | DYLIB_INSTALL_NAME_BASE = "@rpath";
1011 | GCC_PREPROCESSOR_DEFINITIONS = (
1012 | "DEBUG=1",
1013 | "$(inherited)",
1014 | );
1015 | INFOPLIST_FILE = LTMorphingLabel/Info.plist;
1016 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1017 | LD_RUNPATH_SEARCH_PATHS = (
1018 | "$(inherited)",
1019 | "@executable_path/Frameworks",
1020 | "@loader_path/Frameworks",
1021 | );
1022 | MTL_ENABLE_DEBUG_INFO = YES;
1023 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
1024 | PRODUCT_NAME = MorphingLabel;
1025 | PROVISIONING_PROFILE_SPECIFIER = "";
1026 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
1027 | SKIP_INSTALL = YES;
1028 | TARGETED_DEVICE_FAMILY = "1,2";
1029 | VERSIONING_SYSTEM = "apple-generic";
1030 | VERSION_INFO_PREFIX = "";
1031 | };
1032 | name = Debug;
1033 | };
1034 | D7D4B03A1A5E87D50087F83D /* Release */ = {
1035 | isa = XCBuildConfiguration;
1036 | buildSettings = {
1037 | APPLICATION_EXTENSION_API_ONLY = YES;
1038 | CODE_SIGN_IDENTITY = "";
1039 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
1040 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
1041 | CODE_SIGN_STYLE = Manual;
1042 | CURRENT_PROJECT_VERSION = 1;
1043 | DEFINES_MODULE = YES;
1044 | DEVELOPMENT_TEAM = "";
1045 | DYLIB_COMPATIBILITY_VERSION = 1;
1046 | DYLIB_CURRENT_VERSION = 1;
1047 | DYLIB_INSTALL_NAME_BASE = "@rpath";
1048 | INFOPLIST_FILE = LTMorphingLabel/Info.plist;
1049 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
1050 | LD_RUNPATH_SEARCH_PATHS = (
1051 | "$(inherited)",
1052 | "@executable_path/Frameworks",
1053 | "@loader_path/Frameworks",
1054 | );
1055 | MTL_ENABLE_DEBUG_INFO = NO;
1056 | PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
1057 | PRODUCT_NAME = MorphingLabel;
1058 | PROVISIONING_PROFILE_SPECIFIER = "";
1059 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
1060 | SKIP_INSTALL = YES;
1061 | TARGETED_DEVICE_FAMILY = "1,2";
1062 | VERSIONING_SYSTEM = "apple-generic";
1063 | VERSION_INFO_PREFIX = "";
1064 | };
1065 | name = Release;
1066 | };
1067 | /* End XCBuildConfiguration section */
1068 |
1069 | /* Begin XCConfigurationList section */
1070 | D73DFD171F4DB5CC00F84122 /* Build configuration list for PBXNativeTarget "MorphingLabel_tvOS" */ = {
1071 | isa = XCConfigurationList;
1072 | buildConfigurations = (
1073 | D73DFD181F4DB5CC00F84122 /* Debug */,
1074 | D73DFD191F4DB5CC00F84122 /* Release */,
1075 | );
1076 | defaultConfigurationIsVisible = 0;
1077 | defaultConfigurationName = Release;
1078 | };
1079 | D73DFD291F5056A700F84122 /* Build configuration list for PBXNativeTarget "LTMorphingLabelUITests" */ = {
1080 | isa = XCConfigurationList;
1081 | buildConfigurations = (
1082 | D73DFD271F5056A700F84122 /* Debug */,
1083 | D73DFD281F5056A700F84122 /* Release */,
1084 | );
1085 | defaultConfigurationIsVisible = 0;
1086 | defaultConfigurationName = Release;
1087 | };
1088 | D74AD969195171E7009A2ACD /* Build configuration list for PBXProject "LTMorphingLabelDemo" */ = {
1089 | isa = XCConfigurationList;
1090 | buildConfigurations = (
1091 | D74AD983195171E7009A2ACD /* Debug */,
1092 | D74AD984195171E7009A2ACD /* Release */,
1093 | );
1094 | defaultConfigurationIsVisible = 0;
1095 | defaultConfigurationName = Release;
1096 | };
1097 | D74AD985195171E7009A2ACD /* Build configuration list for PBXNativeTarget "LTMorphingLabelDemo" */ = {
1098 | isa = XCConfigurationList;
1099 | buildConfigurations = (
1100 | D74AD986195171E7009A2ACD /* Debug */,
1101 | D74AD987195171E7009A2ACD /* Release */,
1102 | );
1103 | defaultConfigurationIsVisible = 0;
1104 | defaultConfigurationName = Release;
1105 | };
1106 | D7934DD11A63AF1100AE04CE /* Build configuration list for PBXNativeTarget "LTMorphingLabelTests" */ = {
1107 | isa = XCConfigurationList;
1108 | buildConfigurations = (
1109 | D7934DCF1A63AF1100AE04CE /* Debug */,
1110 | D7934DD01A63AF1100AE04CE /* Release */,
1111 | );
1112 | defaultConfigurationIsVisible = 0;
1113 | defaultConfigurationName = Release;
1114 | };
1115 | D7D4B03D1A5E87D50087F83D /* Build configuration list for PBXNativeTarget "MorphingLabel" */ = {
1116 | isa = XCConfigurationList;
1117 | buildConfigurations = (
1118 | D7D4B0391A5E87D50087F83D /* Debug */,
1119 | D7D4B03A1A5E87D50087F83D /* Release */,
1120 | );
1121 | defaultConfigurationIsVisible = 0;
1122 | defaultConfigurationName = Release;
1123 | };
1124 | /* End XCConfigurationList section */
1125 | };
1126 | rootObject = D74AD966195171E7009A2ACD /* Project object */;
1127 | }
1128 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/LTMorphingLabelDemo.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | B5A16937-A9B9-4B6F-B635-3E9C1B270E75
9 | IDESourceControlProjectName
10 | LTMorphingLabelDemo
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | D256575CFF167EE4510B644FB2F3602FDD05F90B
14 | https://github.com/lexrus/LTMorphingLabel.git
15 |
16 | IDESourceControlProjectPath
17 | LTMorphingLabelDemo.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | D256575CFF167EE4510B644FB2F3602FDD05F90B
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/lexrus/LTMorphingLabel.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | D256575CFF167EE4510B644FB2F3602FDD05F90B
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | D256575CFF167EE4510B644FB2F3602FDD05F90B
36 | IDESourceControlWCCName
37 | LTMorphingLabel
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcuserdata/lex.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcuserdata/lex.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/LTMorphingLabelDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
52 |
58 |
59 |
60 |
61 |
62 |
72 |
74 |
80 |
81 |
82 |
83 |
89 |
91 |
97 |
98 |
99 |
100 |
102 |
103 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/MorphingLabel.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 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo.xcodeproj/xcuserdata/lex.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | LTMorphingLabelDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 | LTMorphingLabelDemo.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 | MorphingLabel.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 0
21 |
22 | MorphingLabel_tvOS.xcscheme_^#shared#^_
23 |
24 | orderHint
25 | 2
26 |
27 |
28 | SuppressBuildableAutocreation
29 |
30 | D73DFD001F4DB5CC00F84122
31 |
32 | primary
33 |
34 |
35 | D73DFD1F1F5056A700F84122
36 |
37 | primary
38 |
39 |
40 | D74AD96D195171E7009A2ACD
41 |
42 | primary
43 |
44 |
45 | D7934DC51A63AF1100AE04CE
46 |
47 | primary
48 |
49 |
50 | D7D4B01E1A5E87D50087F83D
51 |
52 | primary
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // LTMorphingLabelDemo
4 | //
5 | // Created by Lex on 6/18/14.
6 | // Copyright (c) 2015 lexrus.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate : UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(
17 | _ application: UIApplication,
18 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
19 | ) -> Bool {
20 | window!.backgroundColor = UIColor.black
21 | window!.makeKeyAndVisible()
22 | return true
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.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 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-60@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-60@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "idiom" : "ipad",
47 | "size" : "20x20",
48 | "scale" : "1x"
49 | },
50 | {
51 | "idiom" : "ipad",
52 | "size" : "20x20",
53 | "scale" : "2x"
54 | },
55 | {
56 | "idiom" : "ipad",
57 | "size" : "29x29",
58 | "scale" : "1x"
59 | },
60 | {
61 | "idiom" : "ipad",
62 | "size" : "29x29",
63 | "scale" : "2x"
64 | },
65 | {
66 | "idiom" : "ipad",
67 | "size" : "40x40",
68 | "scale" : "1x"
69 | },
70 | {
71 | "idiom" : "ipad",
72 | "size" : "40x40",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "76x76",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-76.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "76x76",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-76@2x.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "83.5x83.5",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-83.5@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "idiom" : "ios-marketing",
95 | "size" : "1024x1024",
96 | "scale" : "1x"
97 | }
98 | ],
99 | "info" : {
100 | "version" : 1,
101 | "author" : "xcode"
102 | }
103 | }
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lexrus/LTMorphingLabel/4b80cf8b8ce04f15f8fa0581fd87420e09d4408f/LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | $(PRODUCT_NAME)
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSMainNibFile~ipad
28 | LTMorphingLabelDemo-iPad
29 | UILaunchStoryboardName
30 | Launch Screen
31 | UIMainStoryboardFile
32 | LTMorphingLabelDemo
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UIStatusBarStyle
38 | UIStatusBarStyleLightContent
39 | UISupportedInterfaceOrientations
40 |
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/LTDemoViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTDemoViewController.swift
3 | // LTMorphingLabelDemo
4 | //
5 | // Created by Lex on 6/23/14.
6 | // Copyright (c) 2015 lexrus.com. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LTDemoViewController : UIViewController, LTMorphingLabelDelegate {
12 |
13 | fileprivate var i = -1
14 | fileprivate var textArray = [
15 | "What is design?",
16 | "Design", "Design is not just", "what it looks like", "and feels like.",
17 | "Design", "is how it works.", "- Steve Jobs",
18 | "Older people", "sit down and ask,", "'What is it?'",
19 | "but the boy asks,", "'What can I do with it?'.", "- Steve Jobs",
20 | "One more thing...", "Swift", "Objective-C", "iPhone", "iPad", "Mac Mini",
21 | "MacBook Pro🔥", "Mac Pro⚡️",
22 | "爱老婆",
23 | "नमस्ते दुनिया",
24 | "हिन्दी भाषा",
25 | "$68.98",
26 | "$68.99",
27 | "$69.00",
28 | "$69.01"
29 | ]
30 | fileprivate var text: String {
31 | i = i >= textArray.count - 1 ? 0 : i + 1
32 | return textArray[i]
33 | }
34 |
35 | @IBOutlet weak var effectSegmentControl: UISegmentedControl!
36 | @IBOutlet weak var themeSegmentControl: UISegmentedControl!
37 | @IBOutlet fileprivate var label: LTMorphingLabel!
38 |
39 | override func viewDidLoad() {
40 | super.viewDidLoad()
41 |
42 | label.delegate = self
43 |
44 | [effectSegmentControl, themeSegmentControl].forEach {
45 | $0?.setTitleTextAttributes([.foregroundColor : UIColor.white], for: .normal)
46 | $0?.setTitleTextAttributes([.foregroundColor : UIColor.white], for: .selected)
47 | }
48 | }
49 |
50 | @IBAction func changeText(_ sender: AnyObject) {
51 | label.text = text
52 | if !autoStart.isOn {
53 | label.pause()
54 | progressSlider.value = 0
55 | }
56 | }
57 |
58 | @IBAction func clear(_ sender: Any) {
59 | label.text = nil
60 | }
61 |
62 | @IBOutlet weak var autoStart: UISwitch!
63 |
64 | @IBAction func updateAutoStart(_ sender: Any) {
65 | progressSlider.isHidden = autoStart.isOn
66 | if autoStart.isOn {
67 | label.resume()
68 | } else {
69 | changeText(NSObject())
70 | }
71 | }
72 |
73 | @IBOutlet weak var progressSlider: UISlider!
74 |
75 | @IBAction func updateProgress(_ sender: Any) {
76 | label.morphingProgress = progressSlider.value / 100
77 | label.setNeedsDisplay()
78 | }
79 |
80 | @IBAction func segmentChanged(_ sender: UISegmentedControl) {
81 | let seg = sender
82 | if let effect = LTMorphingEffect(rawValue: seg.selectedSegmentIndex) {
83 | label.morphingEffect = effect
84 | changeText(sender)
85 | }
86 | }
87 |
88 | @IBAction func toggleLight(_ sender: UISegmentedControl) {
89 | let isNight = Bool(sender.selectedSegmentIndex == 0)
90 | view.backgroundColor = isNight ? UIColor.black : UIColor.white
91 | label.textColor = isNight ? UIColor.white : UIColor.black
92 | }
93 |
94 | @IBAction func changeFontSize(_ sender: UISlider) {
95 | label.font = UIFont(descriptor: label.font.fontDescriptor, size: CGFloat(sender.value))
96 | label.text = label.text
97 | }
98 | }
99 |
100 | extension LTDemoViewController {
101 |
102 | func morphingDidStart(_ label: LTMorphingLabel) {
103 |
104 | }
105 |
106 | func morphingDidComplete(_ label: LTMorphingLabel) {
107 |
108 | }
109 |
110 | func morphingOnProgress(_ label: LTMorphingLabel, progress: Float) {
111 |
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/LTMorphingLabelDemo.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 |
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 |
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 |
--------------------------------------------------------------------------------
/LTMorphingLabelDemo/Launch Screen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/LTMorphingLabelTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LTMorphingLabelTests/LTMorphingLabelTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabelTests.swift
3 | // LTMorphingLabelTests
4 | //
5 | // Created by Lex Tang on 1/12/15.
6 | // Copyright (c) 2015 lexrus.com. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MorphingLabel
11 |
12 | class LTMorphingLabelTests : XCTestCase {
13 |
14 | func testStringDiff1() {
15 | let diffResults = "he".diffWith("hello")
16 | XCTAssert(
17 | diffResults.0[0] == .same,
18 | "First character isn't changed."
19 | )
20 | XCTAssert(diffResults.0[2] == .add, "Third character is added.")
21 | }
22 |
23 | func testStringDiff2() {
24 | let diffResults = "news".diffWith("westen")
25 | if case .moveAndAdd(let offset) = diffResults.0[0] {
26 | XCTAssert(
27 | offset == 5,
28 | "n is moved right for 5 steps, not \(offset)."
29 | )
30 | } else {
31 | XCTFail("Failed to move and add.")
32 | }
33 |
34 | if case .moveAndAdd(let offset) = diffResults.0[2] {
35 | XCTAssert(
36 | offset == -2,
37 | "w is moved left for 2 steps, not \(offset)."
38 | )
39 | } else {
40 | XCTFail("Failed to move and add.")
41 | }
42 |
43 | XCTAssert(diffResults.0[4] == .add, "2nd e is added.")
44 | XCTAssert(diffResults.1[5], "The last n was moved in.")
45 | }
46 |
47 | func testStringDiff3() {
48 | let diffResults = "Enchanté".diffWith("Swifter")
49 |
50 | XCTAssert(diffResults.0[4] == .replace, "a is deleted.")
51 | }
52 |
53 | func testStringDiff4() {
54 | let diffResults = "wo".diffWith("ox")
55 | XCTAssert(diffResults.0[0] == .replace, "w is replaced.")
56 | XCTAssert(
57 | diffResults.0[1] == .moveAndAdd(offset: -1),
58 | "o is moved and add a new character."
59 | )
60 | }
61 |
62 | func testStringDiff5() {
63 | let diffResults = "Objective-C".diffWith("iPhone")
64 | XCTAssert(diffResults.0[0] == .replace, "w is replaced.")
65 | XCTAssert(
66 | diffResults.0[3] == .moveAndAdd(offset: 2),
67 | "e is moved and add a new character."
68 | )
69 | XCTAssert(diffResults.0[8] == .delete, "2nd e is deleted.")
70 | }
71 |
72 | func testStringDiff6() {
73 | let diffResults = "wow".diffWith("newwow")
74 | XCTAssert(diffResults.0[2] == .moveAndAdd(offset: 1), "2nd. w is moved.")
75 | }
76 |
77 | func testEmojiDiff7() {
78 | let diffResults = "1️⃣2️⃣3️⃣".diffWith("3️⃣1️⃣2️⃣")
79 | XCTAssert(diffResults.0[0] == .moveAndAdd(offset: 1), "1st. 1 is moved.")
80 | }
81 |
82 | func testEmptyDiff8() {
83 | let diffResults0 = "".diffWith("hello")
84 | XCTAssert(diffResults0.0[0] == .add, "Every characters must be added.")
85 | let diffResults1 = "".diffWith("")
86 | XCTAssert(diffResults1.0.count == 0, "Must be empty.")
87 | let diffResults2 = "Hello".diffWith("")
88 | XCTAssert(diffResults2.0[0] == .delete, "Must be empty.")
89 | }
90 |
91 | func testLongDiffPerformance() {
92 | measure {
93 | let lhs =
94 | "Design is not just what it looks like and feels like."
95 | + "Design is how it works."
96 | let rhs =
97 | "Innovation distinguishes between a leader and a follower."
98 | _ = lhs.diffWith(rhs)
99 | }
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/LTMorphingLabelUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LTMorphingLabelUITests/LTMorphingLabelUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LTMorphingLabelUITests.swift
3 | // LTMorphingLabelUITests
4 | //
5 | // Created by Lex on 25/08/2017.
6 | // Copyright © 2017 lexrus.com. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MorphingLabel
11 |
12 | class LTMorphingLabelUITests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 |
17 | continueAfterFailure = false
18 | XCUIApplication().launch()
19 | }
20 |
21 | override func tearDown() {
22 | super.tearDown()
23 | }
24 |
25 | func testMonkeyTest() {
26 | let app = XCUIApplication()
27 | app.buttons["Evaporate"].tap()
28 |
29 | app.buttons["Fall"].tap()
30 |
31 | let morphinglabelStaticText = XCUIApplication().staticTexts["morphingLabel"]
32 | for _ in 0...20 {
33 | morphinglabelStaticText.tap()
34 | }
35 | }
36 |
37 | func testNilText() {
38 | let app = XCUIApplication()
39 | app.buttons["Clear"].tap()
40 |
41 | let label = app.staticTexts["morphingLabel"]
42 |
43 | guard label.exists else {
44 | XCTFail("must have a morphingLabel with accessibilityIdentifier 'morphingLabel'")
45 | return
46 | }
47 |
48 | app.buttons["Scale"].tap()
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "MorphingLabel",
6 | products: [
7 | .library(name: "MorphingLabel", targets: ["MorphingLabel"]),
8 | .library(name: "MorphingLabelDynamic", type: .dynamic, targets: ["MorphingLabel"]),
9 | .library(name: "MorphinglabelXCFramework", targets: ["LTMorphingLabel"])
10 | ],
11 | targets: [
12 | .target(
13 | name: "MorphingLabel",
14 | exclude: [
15 | "Info.plist",
16 | "tvOS-Info.plist"
17 | ],
18 | resources: [
19 | .process("Particles")
20 | ]
21 | ),
22 | .binaryTarget(
23 | name: "LTMorphingLabel",
24 | url: "https://github.com/lexrus/LTMorphingLabel/releases/download/0.9.3/LTMorphingLabel.xcframework.zip",
25 | checksum: "28a0ed8b7df12c763d45b7dde2aa41fd843984b79e6fbd3750f2fc1a6c247a13"
26 | )
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # LTMorphingLabel
3 |
4 | [](https://travis-ci.org/lexrus/LTMorphingLabel)
5 | 
6 | [](https://github.com/lexrus/LTMorphingLabel)
7 | [](https://github.com/Carthage/Carthage)
8 | [](https://github.com/JamitLabs/Accio)
9 | 
10 |
11 | A morphing UILabel subclass written in Swift, originally designed to mimic [Apple's QuickType animation in iOS 8 at WWDC 2014](https://youtu.be/w87fOAG8fjk?t=3451).
12 |
13 | ## Table of Contents
14 |
15 | - [Available Effects](#available-effects)
16 | - [.scale](#scale-default)
17 | - [.evaporate](#evaporate)
18 | - [.fall](#fall)
19 | - [.pixelate](#pixelate)
20 | - [.sparkle](#sparkle)
21 | - [.burn](#burn)
22 | - [Usage](#usage)
23 | - [UIKit](#uikit)
24 | - [SwiftUI](#swiftui)
25 | - [Requirements](#requirements)
26 | - [Installation](#installation)
27 | - [Swift Package Manager](#swift-package-manager)
28 | - [CocoaPods](#cocoapods)
29 | - [Carthage](#carthage)
30 | - [XCFramework](#xcframework)
31 | - [Accio](#accio)
32 | - [Unit Testing](#unit-testing)
33 | - [Apps Using `LTMorphingLabel`](#apps-using-ltmorphinglabel)
34 | - [Third-Party Ports](#third-party-ports)
35 | - [Android](#android)
36 | - [React Native](#react-native)
37 | - [License](#license)
38 |
39 | ## Available Effects
40 |
41 | #### .scale (_default_)
42 |
43 |
44 | #### [.evaporate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BEvaporate.swift)
45 |
46 |
47 | #### [.fall](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BFall.swift)
48 |
49 |
50 | #### [.pixelate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BPixelate.swift)
51 |
52 |
53 | #### [.sparkle](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BSparkle.swift)
54 |
55 |
56 | > ```.sparkle``` is built on top of `QuartzCore.CAEmitterLayer`. There is also a SpriteKit-powered version [here](https://github.com/lexrus/LTMorphingLabel/blob/spritekit-sparkle/LTMorphingLabel/LTMorphingLabel%2BSparkle.swift).
57 |
58 | #### [.burn](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BBurn.swift)
59 |
60 |
61 | #### [.anvil](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BAnvil.swift)
62 |
63 |
64 | ## Usage
65 |
66 | ### UIKit
67 |
68 | Since `LTMorphingLabel` is a drop-in replacement, you can use it like any `UILabel` by setting its text property, yielding the default effect (`.scale`):
69 |
70 | ```swift
71 | var exampleLabel = LTMorphingLabel()
72 | exampleLabel.text = "This is a test"
73 | ```
74 | 
75 |
76 | Alternatively, it can be used interactively:
77 | ```swift
78 | var exampleLabel = LTMorphingLabel()
79 | exampleLabel.text = "This is a test"
80 | exampleLabel.pause()
81 |
82 | // Call .updateProgress(progress: Float) for interactive animation
83 | // Note: In this case, animation will stop at 45% and will not complete
84 | // unless called later with 100 as the `progress` float value.
85 | exampleLabel.updateProgress(progress: 45.0)
86 | ```
87 |
88 | The effect can be changed by setting the `morphingEffect` property:
89 | ```swift
90 | var exampleLabel = LTMorphingLabel()
91 | exampleLabel.text = "This is a test"
92 | exampleLabel.morphingEffect = .burn
93 | ```
94 | 
95 |
96 | ### SwiftUI
97 |
98 | To use `LTMorphingLabel` in SwiftUI, simply declare it and set its text, `effect`, `font`, and `textColor` properties:
99 | ```swift
100 | public var body: some View {
101 | VStack {
102 | MorphingText(
103 | "This is a test",
104 | font: UIFont.systemFont(ofSize: 20),
105 | textColor: .black,
106 | textAlignment: .center
107 | )
108 | .frame(maxWidth: 200, maxHeight: 100)
109 | }
110 | }
111 | ```
112 |
113 | Similar to its use in UIKit, you can also specify the morphing effect manually (if you do not want to use the default `.scale` effect):
114 | ```swift
115 | public var body: some View {
116 | VStack {
117 | MorphingText(
118 | "This is a test",
119 | effect: .burn, // Specify an alternative morphing effect with this line
120 | font: UIFont.systemFont(ofSize: 20),
121 | textColor: .black,
122 | textAlignment: .center
123 | )
124 | .frame(maxWidth: 200, maxHeight: 100)
125 | }
126 | }
127 | ```
128 | 
129 |
130 | ## Requirements
131 |
132 | - Xcode 12+
133 | - iOS 9.0+ (note that SwiftUI requires iOS 13+)
134 |
135 | ## Installation
136 |
137 | ### [Swift Package Manager](https://swift.org/package-manager/)
138 |
139 | Simply add this library to your package manifest or follow instructions on adding a package dependency [using Xcode here](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app).
140 | ```swift
141 | .package(
142 | url: "https://github.com/lexrus/LTMorphingLabel.git",
143 | .branch("master")
144 | )
145 | ```
146 |
147 | ### [CocoaPods](http://cocoapods.org)
148 |
149 | Add `pod 'LTMorphingLabel'` to your Podfile or follow instructions to add dependencies [here](https://guides.cocoapods.org/using/using-cocoapods.html).
150 |
151 | ### [Carthage](https://github.com/Carthage/Carthage)
152 |
153 | Add `github "lexrus/LTMorphingLabel"` to your Cartfile or follow instructions on adding frameworks [here](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
154 |
155 | ### [XCFramework](https://developer.apple.com/videos/play/wwdc2019/416/)
156 |
157 | A pre-compiled `xcframework` file is available on the [Releases](https://github.com/lexrus/LTMorphingLabel/releases) page.
158 |
159 | ### [Accio](https://github.com/JamitLabs/Accio)
160 |
161 | 1. Add this library to your package manifest (see [Swift Package Manager](#swift-package-manager))
162 |
163 | 2. Update your target dependencies to include `LTMorphingLabel`:
164 |
165 | ```swift
166 | .target(
167 | name: "App",
168 | dependencies: [
169 | "LTMorphingLabel",
170 | ]
171 | ),
172 | ```
173 |
174 | 3. Run `accio update`.
175 |
176 | ## Unit Testing
177 |
178 | Clone the repo by running `git clone https://github.com/lexrus/LTMorphingLabel.git`, then open the project with Xcode and press Cmd + U (or, in the menu bar, click Product > Build for > Testing).
179 |
180 | ## Apps Using `LTMorphingLabel`
181 | - [Idea](https://itunes.apple.com/app/id1286758943) by [Igor Matyushkin](https://github.com/igormatyushkin014)
182 | - [Speedo[kilo]meter](https://itunes.apple.com/it/app/speedo-kilo-meter/id1228840413?mt=8) by [Alberto Pasca](http://www.albertopasca.it/whiletrue)
183 | - [Vatomium](http://vatomium.com) by [Erik Telepovský](http://pragmaticmates.com)
184 | - [Atmos](http://www.atmosapp.com) by [@shnhrrsn](https://github.com/shnhrrsn)
185 | - [The Met Challenge](https://itunes.apple.com/us/app/the-met-challenge/id917662781) by [@lazerwalker](https://github.com/lazerwalker)
186 | - [Uther](https://github.com/callmewhy/Uther) by [@callmewhy](https://github.com/callmewhy)
187 | - [Reax](https://itunes.apple.com/us/app/reax-witness-2016-here.-now./id1076183758?ls=1&mt=8) by Reax Inc
188 | - [Puzzpic](https://itunes.apple.com/us/app/puzzpic/id1092871121) by [Moath Othman](http://moathothman.com)
189 | - [Drops](http://languagedrops.com) by [Mark Aron Szulyovszky](https://github.com/itchingpixels)
190 | - [Setgraph Workout Log](https://itunes.apple.com/us/app/setgraph-workout-log/id1209781676?mt=8) by [Arturo Lee](https://github.com/ArturoLee)
191 | - [Nihon](https://itunes.apple.com/app/id1315486029) by [KyXu](https://github.com/OpenMarshall)
192 | - [Lightsync](https://itunes.apple.com/app/id1463390406?mt=8&ct=ghltml) by [Marcel Braun](https://github.com/thatmarcel)
193 | - [Find](https://apps.apple.com/app/find-command-f-for-camera/id1506500202) by [A. Zheng](https://github.com/aheze)
194 |
195 | ## Third-Party Ports
196 |
197 | ### Android
198 |
199 | The Android port of this library is available [here](https://github.com/hanks-zyh/HTextView).
200 |
201 | ### React Native
202 |
203 | The React Native port of this library is available [here](https://github.com/prscX/react-native-morphing-text).
204 |
205 | ## License
206 |
207 | This code is distributed under the terms and conditions of the MIT license.
208 |
--------------------------------------------------------------------------------
/Sources/MorphingLabel:
--------------------------------------------------------------------------------
1 | ../LTMorphingLabel
--------------------------------------------------------------------------------
/build_xcframework.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PROJECT_FILE="LTMorphingLabelDemo.xcodeproj"
4 | SCHEME="MorphingLabel"
5 | BUILD_FOLDER="Build/MorphingLabel"
6 |
7 | mkdir -p Build
8 |
9 | # iOS Simulator
10 | xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
11 | -archivePath "$BUILD_FOLDER/Simulator" \
12 | -sdk iphonesimulator \
13 | SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
14 |
15 | # iOS
16 | xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
17 | -archivePath "$BUILD_FOLDER/iOS" \
18 | -sdk iphoneos \
19 | SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
20 |
21 | # tvOS
22 | xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
23 | -archivePath "$BUILD_FOLDER/tvOS" \
24 | -sdk appletvos \
25 | SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
26 |
27 | # tvOS Simulator
28 | xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
29 | -archivePath "$BUILD_FOLDER/tvOSSimulator" \
30 | -sdk appletvsimulator \
31 | SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
32 |
33 | # XCFramework
34 | xcodebuild -create-xcframework \
35 | -framework "$BUILD_FOLDER/iOS.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
36 | -framework "$BUILD_FOLDER/tvOS.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
37 | -framework "$BUILD_FOLDER/Simulator.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
38 | -framework "$BUILD_FOLDER/tvOSSimulator.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
39 | -output Build/LTMorphingLabel.xcframework
40 |
41 | cd Build
42 |
43 | # Compress
44 | zip -vry LTMorphingLabel.xcframework.zip LTMorphingLabel.xcframework/ -x "*.DS_Store"
45 |
46 | # Checksum for Package.swift
47 | swift package compute-checksum LTMorphingLabel.xcframework.zip
48 |
49 | # Open in Finder
50 | open ./
51 |
--------------------------------------------------------------------------------