Showing preview only (201K chars total). Download the full file or copy to clipboard to get everything.
Repository: lexrus/LTMorphingLabel
Branch: master
Commit: bf629bd1ea03
Files: 41
Total size: 188.4 KB
Directory structure:
gitextract_90kd__s2/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .swiftlint.yml
├── LICENSE
├── 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
│ ├── SwiftUI/
│ │ └── MorphingText.swift
│ └── tvOS-Info.plist
├── LTMorphingLabel.podspec
├── LTMorphingLabelDemo/
│ ├── AppDelegate.swift
│ ├── Images.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Info.plist
│ ├── LTDemoViewController.swift
│ ├── LTMorphingLabelDemo.storyboard
│ └── Launch Screen.storyboard
├── LTMorphingLabelDemo.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata/
│ └── xcschemes/
│ ├── LTMorphingLabelDemo.xcscheme
│ └── MorphingLabel.xcscheme
├── LTMorphingLabelTests/
│ ├── Info.plist
│ └── LTMorphingLabelTests.swift
├── LTMorphingLabelUITests/
│ ├── Info.plist
│ └── LTMorphingLabelUITests.swift
├── Package.swift
├── README.md
└── build_xcframework.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: ltmorphinglabel
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io/api/osx,carthage,swift
### Carthage ###
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Swift ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
.build/
# CocoaPods - Refactored to standalone file
# Carthage - Refactored to standalone file
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
# End of https://www.gitignore.io/api/osx,carthage,swift
================================================
FILE: .swiftlint.yml
================================================
disabled_rules:
- todo
- force_cast
- trailing_whitespace
- colon
- identifier_name
- type_name
- comma
- closure_parameter_position
excluded:
- Carthage
- Pods
line_length: 120
function_body_length:
- 230
- 300
type_body_length:
- 300
- 600
file_length:
- 600
- 800
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright © 2026 Lex Tang, https://lex.sh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: LTMorphingLabel/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: LTMorphingLabel/LTCharacterDiffResult.swift
================================================
//
// LTCharacterDiffResult.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import Foundation
public enum LTCharacterDiffResult: CustomDebugStringConvertible, Equatable {
case same
case add
case delete
case move(offset: Int)
case moveAndAdd(offset: Int)
case replace
public var debugDescription: String {
switch self {
case .same:
return "The character is unchanged."
case .add:
return "A new character is ADDED."
case .delete:
return "The character is DELETED."
case .move(let offset):
return "The character is MOVED to \(offset)."
case .moveAndAdd(let offset):
return "The character is MOVED to \(offset) and a new character is ADDED."
case .replace:
return "The character is REPLACED with a new character."
}
}
}
public func == (lhs: LTCharacterDiffResult, rhs: LTCharacterDiffResult) -> Bool {
switch (lhs, rhs) {
case (.move(let offset0), .move(let offset1)):
return offset0 == offset1
case (.moveAndAdd(let offset0), .moveAndAdd(let offset1)):
return offset0 == offset1
case (.add, .add):
return true
case (.delete, .delete):
return true
case (.replace, .replace):
return true
case (.same, .same):
return true
default: return false
}
}
================================================
FILE: LTMorphingLabel/LTCharacterLimbo.swift
================================================
//
// LTCharacterLimbo.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
public struct LTCharacterLimbo: CustomDebugStringConvertible {
public let char: Character
public var rect: CGRect
public var alpha: CGFloat
public var size: CGFloat
public var drawingProgress: CGFloat = 0.0
public var debugDescription: String {
return "Character: '\(char)'"
+ "drawIn (\(rect.origin.x), \(rect.origin.y), "
+ "\(rect.size.width)x\(rect.size.height) "
+ "with alpha \(alpha) "
+ "and \(size)pt font."
}
}
================================================
FILE: LTMorphingLabel/LTEasing.swift
================================================
//
// LTEasing.swift
// LTMorphingLabelDemo
//
// Created by Lex on 7/1/14.
// Copyright (c) 2015 lexrus.com. All rights reserved.
//
import Foundation
// http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js
// t = currentTime
// b = beginning
// c = change
// d = duration
public struct LTEasing {
public static func easeOutQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
return { (f: Float) in
return c * (pow(f, 5) + 1.0) + b
}(t / d - 1.0)
}
public static func easeInQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
return { (f: Float) in
c * pow(f, 5) + b
}(t / d)
}
public static func easeOutBack(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
let s: Float = 2.70158
let t2: Float = t / d - 1.0
return Float(c * (t2 * t2 * ((s + 1.0) * t2 + s) + 1.0)) + b
}
public static func easeOutBounce(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
return { (f: Float) in
if f < 1 / 2.75 {
return c * 7.5625 * f * f + b
} else if f < 2 / 2.75 {
let t = f - 1.5 / 2.75
return c * (7.5625 * t * t + 0.75) + b
} else if f < 2.5 / 2.75 {
let t = f - 2.25 / 2.75
return c * (7.5625 * t * t + 0.9375) + b
} else {
let t = f - 2.625 / 2.75
return c * (7.5625 * t * t + 0.984375) + b
}
}(t / d)
}
}
================================================
FILE: LTMorphingLabel/LTEmitterView.swift
================================================
//
// LTEmitterView.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
private func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
private func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l > r
default:
return rhs < lhs
}
}
public struct LTEmitter {
let layer: CAEmitterLayer = {
let layer = CAEmitterLayer()
layer.emitterPosition = CGPoint(x: 10, y: 10)
layer.emitterSize = CGSize(width: 10, height: 1)
layer.renderMode = .unordered
layer.emitterShape = .line
return layer
}()
let cell: CAEmitterCell = {
let cell = CAEmitterCell()
cell.name = "sparkle"
cell.birthRate = 150.0
cell.velocity = 50.0
cell.velocityRange = -80.0
cell.lifetime = 0.16
cell.lifetimeRange = 0.1
cell.emissionLongitude = CGFloat(Double.pi / 2 * 2.0)
cell.emissionRange = CGFloat(Double.pi / 2 * 2.0)
cell.scale = 0.1
cell.yAcceleration = 100
cell.scaleSpeed = -0.06
cell.scaleRange = 0.1
return cell
}()
public var duration: Float = 0.6
init(name: String, particleName: String, duration: Float) {
cell.name = name
self.duration = duration
var image: UIImage?
defer {
cell.contents = image?.cgImage
}
image = UIImage(named: particleName)
if image != nil {
return
}
// Load from Framework
image = UIImage(
named: particleName,
in: Bundle(for: LTMorphingLabel.self),
compatibleWith: nil)
}
public func play() {
if layer.emitterCells?.count > 0 {
return
}
layer.emitterCells = [cell]
let d = DispatchTime.now() + Double(Int64(duration * Float(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: d) { [weak layer] in
layer?.birthRate = 0.0
}
}
public func stop() {
if nil != layer.superlayer {
layer.emitterCells = nil
layer.removeFromSuperlayer()
}
}
func update(_ configureClosure: LTEmitterConfigureClosure? = .none) -> LTEmitter {
configureClosure?(layer, cell)
return self
}
}
public typealias LTEmitterConfigureClosure = (CAEmitterLayer, CAEmitterCell) -> Void
open class LTEmitterView: UIView {
open lazy var emitters: [String: LTEmitter] = {
var _emitters = [String: LTEmitter]()
return _emitters
}()
open func createEmitter(
_ name: String,
particleName: String,
duration: Float,
configureClosure: LTEmitterConfigureClosure?
) -> LTEmitter {
var emitter: LTEmitter
if let e = emitters[name] {
emitter = e
} else {
emitter = LTEmitter(
name: name,
particleName: particleName,
duration: duration
)
configureClosure?(emitter.layer, emitter.cell)
layer.addSublayer(emitter.layer)
emitters.updateValue(emitter, forKey: name)
}
return emitter
}
open func removeAllEmitters() {
emitters.forEach {
$0.value.layer.removeFromSuperlayer()
}
emitters.removeAll(keepingCapacity: false)
}
}
================================================
FILE: LTMorphingLabel/LTMorphingEffect.swift
================================================
//
// LTMorphingEffect.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
@objc public enum LTMorphingEffect
: Int
, CustomStringConvertible
, ExpressibleByIntegerLiteral
, ExpressibleByStringLiteral
, CaseIterable {
public typealias IntegerLiteralType = Int
public typealias StringLiteralType = String
case scale = 0
case evaporate
case fall
case pixelate
case sparkle
case burn
case anvil
public static let allValues = [
"Scale", "Evaporate", "Fall", "Pixelate", "Sparkle", "Burn", "Anvil"
]
public var description: String {
switch self {
case .evaporate:
return "Evaporate"
case .fall:
return "Fall"
case .pixelate:
return "Pixelate"
case .sparkle:
return "Sparkle"
case .burn:
return "Burn"
case .anvil:
return "Anvil"
default:
return "Scale"
}
}
public init(integerLiteral value: Int) {
self = LTMorphingEffect(rawValue: value) ?? .scale
}
public init(stringLiteral value: String) {
self = {
switch value {
case "Evaporate": return .evaporate
case "Fall": return .fall
case "Pixelate": return .pixelate
case "Sparkle": return .sparkle
case "Burn": return .burn
case "Anvil": return .anvil
default: return .scale
}
}()
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Anvil.swift
================================================
//
// LTMorphingLabel+Anvil.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
@objc
func AnvilLoad() {
startClosures["Anvil\(LTMorphingPhases.start)"] = {
self.emitterView.removeAllEmitters()
guard self.newRects.count > 0 else { return }
let centerRect = self.newRects[Int(self.newRects.count / 2)]
_ = self.emitterView.createEmitter(
"leftSmoke",
particleName: "Smoke",
duration: 0.6
) { (layer, cell) in
layer.emitterSize = CGSize(width: 1, height: 1)
layer.emitterPosition = CGPoint(
x: centerRect.origin.x,
y: centerRect.origin.y + centerRect.size.height / 1.3)
layer.renderMode = .unordered
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.scale = self.font.pointSize / 90.0
cell.scaleSpeed = self.font.pointSize / 130
cell.birthRate = 60
cell.velocity = CGFloat(80 + Int(arc4random_uniform(60)))
cell.velocityRange = 100
cell.yAcceleration = -40
cell.xAcceleration = 70
cell.emissionLongitude = CGFloat(-Double.pi / 2)
cell.emissionRange = CGFloat(Double.pi / 4) / 5.0
cell.lifetime = self.morphingDuration * 2.0
cell.spin = 10
cell.alphaSpeed = -0.5 / self.morphingDuration
}
_ = self.emitterView.createEmitter(
"rightSmoke",
particleName: "Smoke",
duration: 0.6
) { (layer, cell) in
layer.emitterSize = CGSize(width: 1, height: 1)
layer.emitterPosition = CGPoint(
x: centerRect.origin.x,
y: centerRect.origin.y + centerRect.size.height / 1.3)
layer.renderMode = .unordered
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.scale = self.font.pointSize / 90.0
cell.scaleSpeed = self.font.pointSize / 130
cell.birthRate = 60
cell.velocity = CGFloat(80 + Int(arc4random_uniform(60)))
cell.velocityRange = 100
cell.yAcceleration = -40
cell.xAcceleration = -70
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.emissionRange = CGFloat(-Double.pi / 4) / 5.0
cell.lifetime = self.morphingDuration * 2.0
cell.spin = -10
cell.alphaSpeed = -0.5 / self.morphingDuration
}
_ = self.emitterView.createEmitter(
"leftFragments",
particleName: "Fragment",
duration: 0.6
) { (layer, cell) in
layer.emitterSize = CGSize(
width: self.font.pointSize,
height: 1
)
layer.emitterPosition = CGPoint(
x: centerRect.origin.x,
y: centerRect.origin.y + centerRect.size.height / 1.3
)
cell.scale = self.font.pointSize / 90.0
cell.scaleSpeed = self.font.pointSize / 40.0
cell.color = self.textColor.cgColor
cell.birthRate = 60
cell.velocity = 350
cell.yAcceleration = 0
cell.xAcceleration = CGFloat(10 * Int(arc4random_uniform(10)))
cell.emissionLongitude = CGFloat(-Double.pi / 2)
cell.emissionRange = CGFloat(Double.pi / 4) / 5.0
cell.alphaSpeed = -2
cell.lifetime = self.morphingDuration
}
_ = self.emitterView.createEmitter(
"rightFragments",
particleName: "Fragment",
duration: 0.6
) { (layer, cell) in
layer.emitterSize = CGSize(
width: self.font.pointSize,
height: 1
)
layer.emitterPosition = CGPoint(
x: centerRect.origin.x,
y: centerRect.origin.y + centerRect.size.height / 1.3)
cell.scale = self.font.pointSize / 90.0
cell.scaleSpeed = self.font.pointSize / 40.0
cell.color = self.textColor.cgColor
cell.birthRate = 60
cell.velocity = 350
cell.yAcceleration = 0
cell.xAcceleration = CGFloat(-10 * Int(arc4random_uniform(10)))
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.emissionRange = CGFloat(-Double.pi / 4) / 5.0
cell.alphaSpeed = -2
cell.lifetime = self.morphingDuration
}
_ = self.emitterView.createEmitter(
"fragments",
particleName: "Fragment",
duration: 0.6
) { (layer, cell) in
layer.emitterSize = CGSize(
width: self.font.pointSize,
height: 1
)
layer.emitterPosition = CGPoint(
x: centerRect.origin.x,
y: centerRect.origin.y + centerRect.size.height / 1.3)
cell.scale = self.font.pointSize / 90.0
cell.scaleSpeed = self.font.pointSize / 40.0
cell.color = self.textColor.cgColor
cell.birthRate = 60
cell.velocity = 250
cell.velocityRange = CGFloat(Int(arc4random_uniform(20)) + 30)
cell.yAcceleration = 500
cell.emissionLongitude = 0
cell.emissionRange = CGFloat(Double.pi / 2)
cell.alphaSpeed = -1
cell.lifetime = self.morphingDuration
}
}
progressClosures["Anvil\(LTMorphingPhases.progress)"] = {
(index: Int, progress: Float, isNewChar: Bool) in
if !isNewChar {
return min(1.0, max(0.0, progress))
}
let j = Float(sin(Float(index))) * 1.7
return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * j))
}
effectClosures["Anvil\(LTMorphingPhases.disappear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.previousRects[index],
alpha: CGFloat(1.0 - progress),
size: self.font.pointSize,
drawingProgress: 0.0)
}
effectClosures["Anvil\(LTMorphingPhases.appear)"] = {
char, index, progress in
var rect = self.newRects[index]
if progress < 1.0 {
let easingValue = LTEasing.easeOutBounce(progress, 0.0, 1.0)
rect.origin.y = CGFloat(Float(rect.origin.y) * easingValue)
}
if progress > self.morphingDuration * 0.5 {
let end = self.morphingDuration * 0.55
self.emitterView.createEmitter(
"fragments",
particleName: "Fragment",
duration: 0.6
) { (_, _) in }.update { (layer, _) in
if progress > end {
layer.birthRate = 0
}
}.play()
self.emitterView.createEmitter(
"leftFragments",
particleName: "Fragment",
duration: 0.6
) { (_, _) in }.update { (layer, _) in
if progress > end {
layer.birthRate = 0
}
}.play()
self.emitterView.createEmitter(
"rightFragments",
particleName: "Fragment",
duration: 0.6
) { (_, _) in }.update { (layer, _) in
if progress > end {
layer.birthRate = 0
}
}.play()
}
if progress > self.morphingDuration * 0.63 {
let end = self.morphingDuration * 0.7
self.emitterView.createEmitter(
"leftSmoke",
particleName: "Smoke",
duration: 0.6
) { (_, _) in }.update { (layer, _) in
if progress > end {
layer.birthRate = 0
}
}.play()
self.emitterView.createEmitter(
"rightSmoke",
particleName: "Smoke",
duration: 0.6
) { (_, _) in }.update { (layer, _) in
if progress > end {
layer.birthRate = 0
}
}.play()
}
return LTCharacterLimbo(
char: char,
rect: rect,
alpha: CGFloat(self.morphingProgress),
size: self.font.pointSize,
drawingProgress: CGFloat(progress)
)
}
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Burn.swift
================================================
//
// LTMorphingLabel+Burn.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
fileprivate func burningImageForCharLimbo(
_ charLimbo: LTCharacterLimbo,
withProgress progress: CGFloat
) -> (UIImage, CGRect) {
let maskedHeight = charLimbo.rect.size.height * max(0.01, progress)
let maskedSize = CGSize(
width: charLimbo.rect.size.width,
height: maskedHeight
)
UIGraphicsBeginImageContextWithOptions(
maskedSize,
false,
UIScreen.main.scale
)
let rect = CGRect(
x: 0,
y: 0,
width: charLimbo.rect.size.width,
height: maskedHeight
)
String(charLimbo.char).draw(in: rect, withAttributes: [
.font: self.font as Any,
.foregroundColor: self.textColor as Any
])
guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
return (UIImage() , .zero)
}
UIGraphicsEndImageContext()
let newRect = CGRect(
x: charLimbo.rect.origin.x,
y: charLimbo.rect.origin.y,
width: charLimbo.rect.size.width,
height: maskedHeight
)
return (newImage, newRect)
}
@objc
func BurnLoad() {
startClosures["Burn\(LTMorphingPhases.start)"] = {
self.emitterView.removeAllEmitters()
}
progressClosures["Burn\(LTMorphingPhases.progress)"] = {
index, progress, isNewChar in
if !isNewChar {
return min(1.0, max(0.0, progress))
}
let j = Float(sin(Float(index))) * 1.5
return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * j))
}
effectClosures["Burn\(LTMorphingPhases.disappear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.previousRects[index],
alpha: CGFloat(1.0 - progress),
size: self.font.pointSize,
drawingProgress: 0.0
)
}
effectClosures["Burn\(LTMorphingPhases.appear)"] = {
char, index, progress in
if char != " " {
let rect = self.newRects[index]
let emitterPosition = CGPoint(
x: rect.origin.x + rect.size.width / 2.0,
y: CGFloat(progress) * rect.size.height / 1.2 + rect.origin.y
)
self.emitterView.createEmitter(
"c\(index)",
particleName: "Fire",
duration: self.morphingDuration
) { (layer, cell) in
layer.emitterSize = CGSize(
width: rect.size.width,
height: 1
)
layer.renderMode = CAEmitterLayerRenderMode.additive
layer.emitterMode = CAEmitterLayerEmitterMode.outline
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.scale = self.font.pointSize / 160.0
cell.scaleSpeed = self.font.pointSize / 100.0
cell.birthRate = Float(self.font.pointSize)
cell.emissionLongitude = CGFloat(arc4random_uniform(30))
cell.emissionRange = CGFloat(Double.pi / 4)
cell.alphaSpeed = self.morphingDuration * -3.0
cell.yAcceleration = 10
cell.velocity = CGFloat(10 + Int(arc4random_uniform(3)))
cell.velocityRange = 10
cell.spin = 0
cell.spinRange = 0
cell.lifetime = self.morphingDuration / 3.0
}.update { (layer, _) in
layer.emitterPosition = emitterPosition
}.play()
self.emitterView.createEmitter(
"s\(index)",
particleName: "Smoke",
duration: self.morphingDuration
) { (layer, cell) in
layer.emitterSize = CGSize(
width: rect.size.width,
height: 10
)
layer.renderMode = CAEmitterLayerRenderMode.additive
layer.emitterMode = CAEmitterLayerEmitterMode.volume
cell.emissionLongitude = CGFloat(Double.pi / 2)
cell.scale = self.font.pointSize / 40.0
cell.scaleSpeed = self.font.pointSize / 100.0
cell.birthRate =
Float(self.font.pointSize)
/ Float(arc4random_uniform(10) + 10)
cell.emissionLongitude = 0
cell.emissionRange = CGFloat(Double.pi / 4)
cell.alphaSpeed = self.morphingDuration * -3
cell.yAcceleration = -5
cell.velocity = CGFloat(20 + Int(arc4random_uniform(15)))
cell.velocityRange = 20
cell.spin = CGFloat(Float(arc4random_uniform(30)) / 10.0)
cell.spinRange = 3
cell.lifetime = self.morphingDuration
}.update { (layer, _) in
layer.emitterPosition = emitterPosition
}.play()
}
return LTCharacterLimbo(
char: char,
rect: self.newRects[index],
alpha: 1.0,
size: self.font.pointSize,
drawingProgress: CGFloat(progress)
)
}
drawingClosures["Burn\(LTMorphingPhases.draw)"] = {
(charLimbo: LTCharacterLimbo) in
if charLimbo.drawingProgress > 0.0 {
let (charImage, rect) = self.burningImageForCharLimbo(
charLimbo,
withProgress: charLimbo.drawingProgress
)
charImage.draw(in: rect)
return true
}
return false
}
skipFramesClosures["Burn\(LTMorphingPhases.skipFrames)"] = {
return 1
}
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Evaporate.swift
================================================
//
// LTMorphingLabel+Evaporate.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
@objc
func EvaporateLoad() {
progressClosures["Evaporate\(LTMorphingPhases.progress)"] = {
(index: Int, _, isNewChar: Bool) in
let j: Int = Int(round(cos(Double(index)) * 1.2))
let delay = isNewChar ? self.morphingCharacterDelay * -1.0 : self.morphingCharacterDelay
return min(1.0, max(0.0, self.morphingProgress + delay * Float(j)))
}
effectClosures["Evaporate\(LTMorphingPhases.disappear)"] = {
char, index, progress in
let newProgress = LTEasing.easeOutQuint(progress, 0.0, 1.0, 1.0)
let yOffset: CGFloat = -0.8 * CGFloat(self.font.pointSize) * CGFloat(newProgress)
let currentRect = self.previousRects[index].offsetBy(dx: 0, dy: yOffset)
let currentAlpha = CGFloat(1.0 - newProgress)
return LTCharacterLimbo(
char: char,
rect: currentRect,
alpha: currentAlpha,
size: self.font.pointSize,
drawingProgress: 0.0)
}
effectClosures["Evaporate\(LTMorphingPhases.appear)"] = {
char, index, progress in
let newProgress = 1.0 - LTEasing.easeOutQuint(progress, 0.0, 1.0)
let yOffset = CGFloat(self.font.pointSize) * CGFloat(newProgress) * 1.2
return LTCharacterLimbo(
char: char,
rect: self.newRects[index].offsetBy(dx: 0, dy: yOffset),
alpha: CGFloat(self.morphingProgress),
size: self.font.pointSize,
drawingProgress: 0.0
)
}
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Fall.swift
================================================
//
// LTMorphingLabel+Fall.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
@objc
func FallLoad() {
progressClosures["Fall\(LTMorphingPhases.progress)"] = {
(index: Int, progress: Float, isNewChar: Bool) in
if isNewChar {
return min(
1.0,
max(
0.0,
progress
- self.morphingCharacterDelay
* Float(index)
/ 1.7
)
)
}
let j: Float = Float(sin(Double(index))) * 1.7
return min(1.0, max(0.0001, progress + self.morphingCharacterDelay * Float(j)))
}
effectClosures["Fall\(LTMorphingPhases.disappear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.previousRects[index],
alpha: CGFloat(1.0 - progress),
size: self.font.pointSize,
drawingProgress: CGFloat(progress))
}
effectClosures["Fall\(LTMorphingPhases.appear)"] = {
char, index, progress in
let currentFontSize = CGFloat(
LTEasing.easeOutQuint(progress, 0.0, Float(self.font.pointSize))
)
let yOffset = CGFloat(self.font.pointSize - currentFontSize)
return LTCharacterLimbo(
char: char,
rect: self.newRects[index].offsetBy(dx: 0, dy: yOffset),
alpha: CGFloat(self.morphingProgress),
size: currentFontSize,
drawingProgress: 0.0
)
}
drawingClosures["Fall\(LTMorphingPhases.draw)"] = {
limbo in
if limbo.drawingProgress > 0.0 {
let context = UIGraphicsGetCurrentContext()
var charRect = limbo.rect
context!.saveGState()
let charCenterX = charRect.origin.x + (charRect.size.width / 2.0)
var charBottomY = charRect.origin.y + charRect.size.height - self.font.pointSize / 6
var charColor: UIColor = self.textColor
// Fall down if drawingProgress is more than 50%
if limbo.drawingProgress > 0.5 {
let ease = CGFloat(
LTEasing.easeInQuint(
Float(limbo.drawingProgress - 0.4),
0.0,
1.0,
0.5
)
)
charBottomY += ease * 10.0
let fadeOutAlpha = min(
1.0,
max(
0.0,
limbo.drawingProgress * -2.0 + 2.0 + 0.01
)
)
charColor = self.textColor.withAlphaComponent(fadeOutAlpha)
}
charRect = CGRect(
x: charRect.size.width / -2.0,
y: charRect.size.height * -1.0 + self.font.pointSize / 6,
width: charRect.size.width,
height: charRect.size.height)
context!.translateBy(x: charCenterX, y: charBottomY)
let angle = Float(sin(Double(limbo.rect.origin.x)) > 0.5 ? 168 : -168)
let rotation = CGFloat(
LTEasing.easeOutBack(
min(
1.0,
Float(limbo.drawingProgress)
),
0.0,
1.0
) * angle
)
context!.rotate(by: rotation * CGFloat(Double.pi) / 180.0)
let s = String(limbo.char)
let attributes: [NSAttributedString.Key: Any] = [
.font: self.font.withSize(limbo.size),
.foregroundColor: charColor
]
s.draw(in: charRect, withAttributes: attributes)
context!.restoreGState()
return true
}
return false
}
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Pixelate.swift
================================================
//
// LTMorphingLabel+Pixelate.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
@objc
func PixelateLoad() {
effectClosures["Pixelate\(LTMorphingPhases.disappear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.previousRects[index],
alpha: CGFloat(1.0 - progress),
size: self.font.pointSize,
drawingProgress: CGFloat(progress))
}
effectClosures["Pixelate\(LTMorphingPhases.appear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.newRects[index],
alpha: CGFloat(progress),
size: self.font.pointSize,
drawingProgress: CGFloat(1.0 - progress)
)
}
drawingClosures["Pixelate\(LTMorphingPhases.draw)"] = {
limbo in
if limbo.drawingProgress > 0.0 {
let charImage = self.pixelateImageForCharLimbo(
limbo,
withBlurRadius: limbo.drawingProgress * 6.0
)
charImage.draw(in: limbo.rect)
return true
}
return false
}
}
fileprivate func pixelateImageForCharLimbo(
_ charLimbo: LTCharacterLimbo,
withBlurRadius blurRadius: CGFloat
) -> UIImage {
let scale = min(UIScreen.main.scale, 1.0 / blurRadius)
UIGraphicsBeginImageContextWithOptions(charLimbo.rect.size, false, scale)
let fadeOutAlpha = min(1.0, max(0.0, charLimbo.drawingProgress * -2.0 + 2.0 + 0.01))
let rect = CGRect(
x: 0,
y: 0,
width: charLimbo.rect.size.width,
height: charLimbo.rect.size.height
)
String(charLimbo.char).draw(in: rect, withAttributes: [
.font: self.font as Any,
.foregroundColor: self.textColor.withAlphaComponent(fadeOutAlpha)
])
guard let newImage = UIGraphicsGetImageFromCurrentImageContext()
else {
return UIImage()
}
UIGraphicsEndImageContext()
return newImage
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel+Sparkle.swift
================================================
//
// LTMorphingLabel+Sparkle.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import UIKit
extension LTMorphingLabel {
fileprivate func maskedImageForCharLimbo(
_ charLimbo: LTCharacterLimbo,
withProgress progress: CGFloat
) -> (UIImage, CGRect) {
let maskedHeight = charLimbo.rect.size.height * max(0.01, progress)
let maskedSize = CGSize(
width: charLimbo.rect.size.width,
height: maskedHeight
)
UIGraphicsBeginImageContextWithOptions(
maskedSize,
false,
UIScreen.main.scale
)
let rect = CGRect(
x: 0,
y: 0,
width: charLimbo.rect.size.width,
height: maskedHeight
)
String(charLimbo.char).draw(in: rect, withAttributes: [
.font: self.font as Any,
.foregroundColor: self.textColor as Any
])
guard let newImage = UIGraphicsGetImageFromCurrentImageContext() else {
return (UIImage(), CGRect.zero)
}
UIGraphicsEndImageContext()
let newRect = CGRect(
x: charLimbo.rect.origin.x,
y: charLimbo.rect.origin.y,
width: charLimbo.rect.size.width,
height: maskedHeight
)
return (newImage, newRect)
}
@objc
func SparkleLoad() {
startClosures["Sparkle\(LTMorphingPhases.start)"] = {
self.emitterView.removeAllEmitters()
}
progressClosures["Sparkle\(LTMorphingPhases.progress)"] = {
(index: Int, progress: Float, isNewChar: Bool) in
if !isNewChar {
return min(1.0, max(0.0, progress))
}
let j = Float(sin(Float(index))) * 1.5
return min(
1.0,
max(
0.0001,
progress + self.morphingCharacterDelay * j
)
)
}
effectClosures["Sparkle\(LTMorphingPhases.disappear)"] = {
char, index, progress in
return LTCharacterLimbo(
char: char,
rect: self.previousRects[index],
alpha: CGFloat(1.0 - progress),
size: self.font.pointSize,
drawingProgress: 0.0)
}
effectClosures["Sparkle\(LTMorphingPhases.appear)"] = {
char, index, progress in
if char != " " {
let rect = self.newRects[index]
let emitterPosition = CGPoint(
x: rect.origin.x + rect.size.width / 2.0,
y: CGFloat(progress) * rect.size.height * 0.9 + rect.origin.y
)
self.emitterView.createEmitter(
"c\(index)",
particleName: "Sparkle",
duration: self.morphingDuration
) { (layer, cell) in
layer.emitterSize = CGSize(
width: rect.size.width,
height: 1
)
layer.renderMode = .unordered
cell.emissionLongitude = CGFloat(Double.pi / 2.0)
cell.scale = self.font.pointSize / 300.0
cell.scaleSpeed = self.font.pointSize / 300.0 * -1.5
cell.color = self.textColor.cgColor
cell.birthRate =
Float(self.font.pointSize)
* Float(arc4random_uniform(7) + 3)
}.update { (layer, _) in
layer.emitterPosition = emitterPosition
}.play()
}
return LTCharacterLimbo(
char: char,
rect: self.newRects[index],
alpha: CGFloat(self.morphingProgress),
size: self.font.pointSize,
drawingProgress: CGFloat(progress)
)
}
drawingClosures["Sparkle\(LTMorphingPhases.draw)"] = {
(charLimbo: LTCharacterLimbo) in
if charLimbo.drawingProgress > 0.0 {
let (charImage, rect) = self.maskedImageForCharLimbo(
charLimbo,
withProgress: charLimbo.drawingProgress
)
charImage.draw(in: rect)
return true
}
return false
}
skipFramesClosures["Sparkle\(LTMorphingPhases.skipFrames)"] = {
return 1
}
}
}
================================================
FILE: LTMorphingLabel/LTMorphingLabel.h
================================================
//
// LTMorphingLabel.h
// LTMorphingLabel
//
// Created by Lex Tang on 1/8/15.
// Copyright (c) 2015 lexrus.com. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for LTMorphingLabel.
FOUNDATION_EXPORT double LTMorphingLabelVersionNumber;
//! Project version string for LTMorphingLabel.
FOUNDATION_EXPORT const unsigned char LTMorphingLabelVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <LTMorphingLabel/PublicHeader.h>
================================================
FILE: LTMorphingLabel/LTMorphingLabel.swift
================================================
//
// LTMorphingLabel.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import Foundation
import UIKit
import QuartzCore
private func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
private func >= <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l >= r
default:
return !(lhs < rhs)
}
}
enum LTMorphingPhases: Int {
case start, appear, disappear, draw, progress, skipFrames
}
typealias LTMorphingStartClosure =
() -> Void
typealias LTMorphingEffectClosure =
(Character, _ index: Int, _ progress: Float) -> LTCharacterLimbo
typealias LTMorphingDrawingClosure =
(LTCharacterLimbo) -> Bool
typealias LTMorphingManipulateProgressClosure =
(_ index: Int, _ progress: Float, _ isNewChar: Bool) -> Float
typealias LTMorphingSkipFramesClosure =
() -> Int
@objc public protocol LTMorphingLabelDelegate {
@objc optional func morphingDidStart(_ label: LTMorphingLabel)
@objc optional func morphingDidComplete(_ label: LTMorphingLabel)
@objc optional func morphingOnProgress(_ label: LTMorphingLabel, progress: Float)
}
// MARK: - LTMorphingLabel
@IBDesignable open class LTMorphingLabel: UILabel {
@IBInspectable open var morphingProgress: Float = 0.0
@IBInspectable open var morphingDuration: Float = 0.6
@IBInspectable open var morphingCharacterDelay: Float = 0.026
@IBInspectable open var morphingEnabled: Bool = true
@IBOutlet open weak var delegate: LTMorphingLabelDelegate?
open var morphingEffect: LTMorphingEffect = .scale
var startClosures = [String: LTMorphingStartClosure]()
var effectClosures = [String: LTMorphingEffectClosure]()
var drawingClosures = [String: LTMorphingDrawingClosure]()
var progressClosures = [String: LTMorphingManipulateProgressClosure]()
var skipFramesClosures = [String: LTMorphingSkipFramesClosure]()
var diffResults: LTStringDiffResult?
var previousText = ""
var currentFrame = 0
var totalFrames = 0
var totalDelayFrames = 0
var totalWidth: Float = 0.0
var previousRects = [CGRect]()
var newRects = [CGRect]()
var charHeight: CGFloat = 0.0
var skipFramesCount: Int = 0
fileprivate var displayLink: CADisplayLink?
private var tempRenderMorphingEnabled = true
#if TARGET_INTERFACE_BUILDER
let presentingInIB = true
#else
let presentingInIB = false
#endif
override open var font: UIFont! {
get {
return super.font ?? UIFont.systemFont(ofSize: 15)
}
set {
super.font = newValue
setNeedsLayout()
}
}
override open var text: String? {
get {
return super.text ?? ""
}
set {
guard text != newValue else { return }
previousText = text ?? ""
diffResults = previousText.diffWith(newValue)
super.text = newValue ?? ""
morphingProgress = 0.0
currentFrame = 0
totalFrames = 0
tempRenderMorphingEnabled = morphingEnabled
setNeedsLayout()
if !morphingEnabled {
return
}
if presentingInIB {
morphingDuration = 0.01
morphingProgress = 0.5
} else if previousText != text {
start()
let closureKey = "\(morphingEffect.description)\(LTMorphingPhases.start)"
if let closure = startClosures[closureKey] {
return closure()
}
delegate?.morphingDidStart?(self)
}
}
}
open func start() {
guard displayLink == nil else { return }
displayLink = CADisplayLink(target: self, selector: #selector(displayFrameTick))
displayLink?.add(to: .current, forMode: .common)
}
open func pause() {
displayLink?.isPaused = true
}
open func resume() {
displayLink?.isPaused = false
}
open func finish() {
displayLink?.isPaused = false
}
open func stop() {
displayLink?.remove(from: .current, forMode: .common)
displayLink?.invalidate()
displayLink = nil
}
open var textAttributes: [NSAttributedString.Key: Any]? {
didSet {
setNeedsLayout()
}
}
open override func setNeedsLayout() {
super.setNeedsLayout()
previousRects = rectsOfEachCharacter(previousText, withFont: font)
newRects = rectsOfEachCharacter(text ?? "", withFont: font)
}
override open var bounds: CGRect {
get {
return super.bounds
}
set {
super.bounds = newValue
setNeedsLayout()
}
}
override open var frame: CGRect {
get {
return super.frame
}
set {
super.frame = newValue
setNeedsLayout()
}
}
deinit {
stop()
}
lazy var emitterView: LTEmitterView = {
let emitterView = LTEmitterView(frame: self.bounds)
self.addSubview(emitterView)
return emitterView
}()
}
// MARK: - Animation extension
extension LTMorphingLabel {
public func updateProgress(progress: Float) {
guard let displayLink = displayLink else { return }
if displayLink.duration > 0.0 && totalFrames == 0 {
var frameRate = Float(0)
if #available(iOS 10.0, tvOS 10.0, *) {
var frameInterval = 1
if displayLink.preferredFramesPerSecond == 60 {
frameInterval = 1
} else if displayLink.preferredFramesPerSecond == 30 {
frameInterval = 2
} else {
frameInterval = 1
}
frameRate = Float(displayLink.duration) / Float(frameInterval)
} else {
frameRate = Float(displayLink.duration) / Float(displayLink.frameInterval)
}
totalFrames = Int(ceil(morphingDuration / frameRate))
let totalDelay = Float((text!).count) * morphingCharacterDelay
totalDelayFrames = Int(ceil(totalDelay / frameRate))
}
currentFrame = Int(ceil(progress * Float(totalFrames)))
if previousText != text && currentFrame < totalFrames + totalDelayFrames + 10 {
morphingProgress = progress
let closureKey = "\(morphingEffect.description)\(LTMorphingPhases.skipFrames)"
if let closure = skipFramesClosures[closureKey] {
skipFramesCount += 1
if skipFramesCount > closure() {
skipFramesCount = 0
setNeedsDisplay()
}
} else {
setNeedsDisplay()
}
if let onProgress = delegate?.morphingOnProgress {
onProgress(self, morphingProgress)
}
} else {
stop()
delegate?.morphingDidComplete?(self)
}
}
@objc func displayFrameTick() {
if totalFrames == 0 {
updateProgress(progress: 0)
} else {
morphingProgress += 1.0 / Float(totalFrames)
updateProgress(progress: morphingProgress)
}
}
// Could be enhanced by kerning text:
// http://stackoverflow.com/questions/21443625/core-text-calculate-letter-frame-in-ios
func rectsOfEachCharacter(_ textToDraw: String, withFont font: UIFont) -> [CGRect] {
var charRects = [CGRect]()
var leftOffset: CGFloat = 0.0
charHeight = "Leg".size(withAttributes: [.font: font]).height
let topOffset = (bounds.size.height - charHeight) / 2.0
for char in textToDraw {
let charSize = String(char).size(withAttributes: [.font: font])
charRects.append(
CGRect(
origin: CGPoint(
x: leftOffset,
y: topOffset
),
size: charSize
)
)
leftOffset += charSize.width
}
totalWidth = Float(leftOffset)
var stringLeftOffSet: CGFloat = 0.0
switch textAlignment {
case .center:
stringLeftOffSet = CGFloat((Float(bounds.size.width) - totalWidth) / 2.0)
case .right:
stringLeftOffSet = CGFloat(Float(bounds.size.width) - totalWidth)
default:
()
}
var offsetedCharRects = [CGRect]()
for r in charRects {
offsetedCharRects.append(r.offsetBy(dx: stringLeftOffSet, dy: 0.0))
}
return offsetedCharRects
}
func limboOfOriginalCharacter(
_ char: Character,
index: Int,
progress: Float) -> LTCharacterLimbo {
var currentRect = previousRects[index]
let oriX = Float(currentRect.origin.x)
var newX = Float(currentRect.origin.x)
let diffResult = diffResults!.0[index]
var currentFontSize: CGFloat = font.pointSize
var currentAlpha: CGFloat = 1.0
switch diffResult {
// Move the character that exists in the new text to current position
case .same:
newX = Float(newRects[index].origin.x)
currentRect.origin.x = CGFloat(
LTEasing.easeOutQuint(progress, oriX, newX - oriX)
)
case .move(let offset):
newX = Float(newRects[index + offset].origin.x)
currentRect.origin.x = CGFloat(
LTEasing.easeOutQuint(progress, oriX, newX - oriX)
)
case .moveAndAdd(let offset):
newX = Float(newRects[index + offset].origin.x)
currentRect.origin.x = CGFloat(
LTEasing.easeOutQuint(progress, oriX, newX - oriX)
)
default:
// Otherwise, remove it
// Override morphing effect with closure in extenstions
if let closure = effectClosures[
"\(morphingEffect.description)\(LTMorphingPhases.disappear)"
] {
return closure(char, index, progress)
} else {
// And scale it by default
let fontEase = CGFloat(
LTEasing.easeOutQuint(
progress, 0, Float(font.pointSize)
)
)
// For emojis
currentFontSize = max(0.0001, font.pointSize - fontEase)
currentAlpha = CGFloat(1.0 - progress)
currentRect = previousRects[index].offsetBy(
dx: 0,
dy: CGFloat(font.pointSize - currentFontSize)
)
}
}
return LTCharacterLimbo(
char: char,
rect: currentRect,
alpha: currentAlpha,
size: currentFontSize,
drawingProgress: 0.0
)
}
func limboOfNewCharacter(
_ char: Character,
index: Int,
progress: Float) -> LTCharacterLimbo {
let currentRect = newRects[index]
var currentFontSize = CGFloat(
LTEasing.easeOutQuint(progress, 0, Float(font.pointSize))
)
if let closure = effectClosures[
"\(morphingEffect.description)\(LTMorphingPhases.appear)"
] {
return closure(char, index, progress)
} else {
currentFontSize = CGFloat(
LTEasing.easeOutQuint(progress, 0.0, Float(font.pointSize))
)
// For emojis
currentFontSize = max(0.0001, currentFontSize)
let yOffset = CGFloat(font.pointSize - currentFontSize)
return LTCharacterLimbo(
char: char,
rect: currentRect.offsetBy(dx: 0, dy: yOffset),
alpha: CGFloat(morphingProgress),
size: currentFontSize,
drawingProgress: 0.0
)
}
}
func limboOfCharacters() -> [LTCharacterLimbo] {
var limbo = [LTCharacterLimbo]()
// Iterate original characters
for (i, character) in previousText.enumerated() {
var progress: Float = 0.0
if let closure = progressClosures[
"\(morphingEffect.description)\(LTMorphingPhases.progress)"
] {
progress = closure(i, morphingProgress, false)
} else {
progress = min(1.0, max(0.0, morphingProgress + morphingCharacterDelay * Float(i)))
}
let limboOfCharacter = limboOfOriginalCharacter(character, index: i, progress: progress)
limbo.append(limboOfCharacter)
}
// Add new characters
for (i, character) in (text!).enumerated() {
if i >= diffResults?.0.count {
break
}
var progress: Float = 0.0
if let closure = progressClosures[
"\(morphingEffect.description)\(LTMorphingPhases.progress)"
] {
progress = closure(i, morphingProgress, true)
} else {
progress = min(1.0, max(0.0, morphingProgress - morphingCharacterDelay * Float(i)))
}
// Don't draw character that already exists
if diffResults?.skipDrawingResults[i] == true {
continue
}
if let diffResult = diffResults?.0[i] {
switch diffResult {
case .moveAndAdd, .replace, .add, .delete:
let limboOfCharacter = limboOfNewCharacter(
character,
index: i,
progress: progress
)
limbo.append(limboOfCharacter)
default:
()
}
}
}
return limbo
}
}
// MARK: - Drawing extension
extension LTMorphingLabel {
override open func didMoveToSuperview() {
guard nil != superview else {
stop()
return
}
if let s = text {
text = s
}
// Load all morphing effects
for effectName: String in LTMorphingEffect.allValues {
let effectFunc = Selector("\(effectName)Load")
if responds(to: effectFunc) {
perform(effectFunc)
}
}
}
override open func drawText(in rect: CGRect) {
if !tempRenderMorphingEnabled || limboOfCharacters().count == 0 {
super.drawText(in: rect)
return
}
for charLimbo in limboOfCharacters() {
let charRect = charLimbo.rect
let willAvoidDefaultDrawing: Bool = {
if let closure = drawingClosures[
"\(morphingEffect.description)\(LTMorphingPhases.draw)"
] {
return closure($0)
}
return false
}(charLimbo)
if !willAvoidDefaultDrawing {
var attrs: [NSAttributedString.Key: Any] = [
.foregroundColor: textColor.withAlphaComponent(charLimbo.alpha)
]
attrs[.font] = UIFont(descriptor: font.fontDescriptor, size: charLimbo.size)
for (key, value) in textAttributes ?? [:] {
attrs[key] = value
}
let s = String(charLimbo.char)
s.draw(in: charRect, withAttributes: attrs)
}
}
}
}
================================================
FILE: LTMorphingLabel/LTStringDiffResult.swift
================================================
//
// LTStringDiffResult.swift
// https://github.com/lexrus/LTMorphingLabel
//
// The MIT License (MIT)
// Copyright (c) 2017 Lex Tang, http://lexrus.com
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files
// (the “Software”), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import Foundation
public typealias LTStringDiffResult = ([LTCharacterDiffResult], skipDrawingResults: [Bool])
public extension String {
func diffWith(_ anotherString: String?) -> LTStringDiffResult {
guard let anotherString = anotherString else {
let diffResults: [LTCharacterDiffResult] =
Array(repeating: .delete, count: self.count)
let skipDrawingResults: [Bool] = Array(repeating: false, count: self.count)
return (diffResults, skipDrawingResults)
}
let newChars = anotherString.enumerated()
let lhsLength = self.count
let rhsLength = anotherString.count
var skipIndexes = [Int]()
let leftChars = Array(self)
let maxLength = max(lhsLength, rhsLength)
var diffResults: [LTCharacterDiffResult] = Array(repeating: .add, count: maxLength)
var skipDrawingResults: [Bool] = Array(repeating: false, count: maxLength)
for i in 0..<maxLength {
// If new string is longer than the original one
if i > lhsLength - 1 {
continue
}
let leftChar = leftChars[i]
// Search left character in the new string
var foundCharacterInRhs = false
for (j, newChar) in newChars {
if skipIndexes.contains(j) || leftChar != newChar {
continue
}
skipIndexes.append(j)
foundCharacterInRhs = true
if i == j {
// Character not changed
diffResults[i] = .same
} else {
// foundCharacterInRhs and move
let offset = j - i
if i <= rhsLength - 1 {
// Move to a new index and add a new character to new original place
diffResults[i] = .moveAndAdd(offset: offset)
} else {
diffResults[i] = .move(offset: offset)
}
skipDrawingResults[j] = true
}
break
}
if !foundCharacterInRhs {
if i < rhsLength - 1 {
diffResults[i] = .replace
} else {
diffResults[i] = .delete
}
}
}
return (diffResults, skipDrawingResults)
}
}
================================================
FILE: LTMorphingLabel/SwiftUI/MorphingText.swift
================================================
//
// MorphingText.swift
// LTMorphingLabel
//
// Created by Lex on 2020/5/10.
// Copyright © 2020 lexrus.com. All rights reserved.
//
#if canImport(SwiftUI)
import SwiftUI
#endif
@available(iOS 13.0.0, *)
public struct MorphingText: UIViewRepresentable {
public typealias UIViewType = LTMorphingLabel
var text: String
var morphingEffect: LTMorphingEffect
var moprhingEnabled: Bool = true
var font: UIFont
var textColor: UIColor
var textAlignment: NSTextAlignment
public init(_ text: String,
effect: LTMorphingEffect = .scale,
font: UIFont = .systemFont(ofSize: 16),
textColor: UIColor = .black,
textAlignment: NSTextAlignment = .center
) {
self.text = text
self.morphingEffect = effect
self.font = font
self.textColor = textColor
self.textAlignment = textAlignment
}
public func makeUIView(context: Context) -> UIViewType {
let label = LTMorphingLabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
label.textAlignment = .center
label.textColor = UIColor.white
return label
}
public func updateUIView(_ uiView: UIViewType, context: Context) {
uiView.text = text
uiView.font = font
uiView.morphingEnabled = moprhingEnabled
uiView.morphingEffect = morphingEffect
uiView.textColor = textColor
uiView.textAlignment = textAlignment
}
}
@available(iOS 13.0.0, *)
struct MorphingText_Previews: PreviewProvider {
static var previews: some View {
PreviewWrapper()
.previewDevice("iPhone SE")
.environment(\.colorScheme, .dark)
}
struct PreviewWrapper: View {
@State var morphingEnabled = true
@State var textIndex: Double = 0
@State var effectIndex: Double = 0
private var textArray = [
"Supercalifragilisticexpialidocious",
"Stay hungry, stay foolish.",
"Love what you do and do what you love.",
"Apple doesn't do hobbies as a general rule.",
"iOS",
"iPhone",
"iPhone 11",
"iPhone 11 Pro",
"iPhone 11 Pro Max",
"$9995.00",
"$9996.00",
"$9997.00",
"$9998.00",
"$9999.00",
"$10000.00"
]
public var body: some View {
VStack {
Spacer()
Text("LTMorphingLabel").font(.largeTitle)
Text("for SwiftUI").font(.title)
MorphingText(
textArray[Int(round(textIndex))],
effect: LTMorphingEffect.allCases[Int(round(effectIndex))],
font: UIFont.systemFont(ofSize: 20),
textColor: .white
)
.frame(maxWidth: 200, maxHeight: 100)
Text("Effect: \(LTMorphingEffect.allCases[Int(round(effectIndex))].description)").font(.title)
Slider(value: $effectIndex, in: 0...Double(LTMorphingEffect.allCases.count - 1))
Slider(value: $textIndex, in: 0...Double(textArray.count - 1))
Toggle("MorphingEnabled", isOn: $morphingEnabled)
Spacer()
}
.padding(20)
.foregroundColor(Color.white)
.background(Color.black)
}
}
}
================================================
FILE: LTMorphingLabel/tvOS-Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: LTMorphingLabel.podspec
================================================
Pod::Spec.new do |s|
s.name = "LTMorphingLabel"
s.version = "0.9.3"
s.summary = "Graceful morphing effects for UILabel written in Swift."
s.description = <<-DESC
A morphing UILabel subclass written in Swift.
The .Scale effect mimicked Apple's QuickType animation of iOS
8 in WWDC 2014. New morphing effects are available as
Swift extensions.
DESC
s.homepage = "https://github.com/lexrus/LTMorphingLabel"
s.screenshots = "https://cloud.githubusercontent.com/assets/219689/3491822/96bf5de6-059d-11e4-9826-a6f82025d1af.gif",
"https://cloud.githubusercontent.com/assets/219689/3491838/ffc5aff2-059d-11e4-970c-6e2d7664785a.gif",
"https://cloud.githubusercontent.com/assets/219689/3491840/173c2238-059e-11e4-9b33-dcd21edae9e2.gif",
"https://cloud.githubusercontent.com/assets/219689/3491845/29bb0f8c-059e-11e4-9ef8-de56bec1baba.gif",
"https://cloud.githubusercontent.com/assets/219689/3508789/31e9fafe-0690-11e4-9a76-ba3ef45eb53a.gif",
"https://cloud.githubusercontent.com/assets/219689/3594949/815cd3e8-0caa-11e4-9738-278a9c959478.gif"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Lex Tang" => "lexrus@gmail.com" }
s.social_media_url = "https://x.com/lexrus"
s.ios.deployment_target = "9.0"
s.tvos.deployment_target = "9.0"
s.swift_versions = ['5.3']
s.source = {
:git => "https://github.com/lexrus/LTMorphingLabel.git",
:tag => s.version
}
s.source_files = "LTMorphingLabel/*.{h,swift}", "LTMorphingLabel/**/*.{swift}"
s.resources = "LTMorphingLabel/Particles/*.png"
s.frameworks = "UIKit", "Foundation", "QuartzCore"
s.requires_arc = true
end
================================================
FILE: LTMorphingLabelDemo/AppDelegate.swift
================================================
//
// AppDelegate.swift
// LTMorphingLabelDemo
//
// Created by Lex on 6/18/14.
// Copyright (c) 2015 lexrus.com. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
window!.backgroundColor = UIColor.black
window!.makeKeyAndVisible()
return true
}
}
================================================
FILE: LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-60@3x.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-83.5@2x.png",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: LTMorphingLabelDemo/Images.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: LTMorphingLabelDemo/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMainNibFile~ipad</key>
<string>LTMorphingLabelDemo-iPad</string>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIMainStoryboardFile</key>
<string>LTMorphingLabelDemo</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: LTMorphingLabelDemo/LTDemoViewController.swift
================================================
//
// LTDemoViewController.swift
// LTMorphingLabelDemo
//
// Created by Lex on 6/23/14.
// Copyright (c) 2015 lexrus.com. All rights reserved.
//
import UIKit
class LTDemoViewController : UIViewController, LTMorphingLabelDelegate {
fileprivate var i = -1
fileprivate var textArray = [
"What is design?",
"Design", "Design is not just", "what it looks like", "and feels like.",
"Design", "is how it works.", "- Steve Jobs",
"Older people", "sit down and ask,", "'What is it?'",
"but the boy asks,", "'What can I do with it?'.", "- Steve Jobs",
"One more thing...", "Swift", "Objective-C", "iPhone", "iPad", "Mac Mini",
"MacBook Pro🔥", "Mac Pro⚡️",
"爱老婆",
"नमस्ते दुनिया",
"हिन्दी भाषा",
"$68.98",
"$68.99",
"$69.00",
"$69.01"
]
fileprivate var text: String {
i = i >= textArray.count - 1 ? 0 : i + 1
return textArray[i]
}
@IBOutlet weak var effectSegmentControl: UISegmentedControl!
@IBOutlet weak var themeSegmentControl: UISegmentedControl!
@IBOutlet fileprivate var label: LTMorphingLabel!
override func viewDidLoad() {
super.viewDidLoad()
label.delegate = self
[effectSegmentControl, themeSegmentControl].forEach {
$0?.setTitleTextAttributes([.foregroundColor : UIColor.white], for: .normal)
$0?.setTitleTextAttributes([.foregroundColor : UIColor.white], for: .selected)
}
}
@IBAction func changeText(_ sender: AnyObject) {
label.text = text
if !autoStart.isOn {
label.pause()
progressSlider.value = 0
}
}
@IBAction func clear(_ sender: Any) {
label.text = nil
}
@IBOutlet weak var autoStart: UISwitch!
@IBAction func updateAutoStart(_ sender: Any) {
progressSlider.isHidden = autoStart.isOn
if autoStart.isOn {
label.resume()
} else {
changeText(NSObject())
}
}
@IBOutlet weak var progressSlider: UISlider!
@IBAction func updateProgress(_ sender: Any) {
label.morphingProgress = progressSlider.value / 100
label.setNeedsDisplay()
}
@IBAction func segmentChanged(_ sender: UISegmentedControl) {
let seg = sender
if let effect = LTMorphingEffect(rawValue: seg.selectedSegmentIndex) {
label.morphingEffect = effect
changeText(sender)
}
}
@IBAction func toggleLight(_ sender: UISegmentedControl) {
let isNight = Bool(sender.selectedSegmentIndex == 0)
view.backgroundColor = isNight ? UIColor.black : UIColor.white
label.textColor = isNight ? UIColor.white : UIColor.black
}
@IBAction func changeFontSize(_ sender: UISlider) {
label.font = UIFont(descriptor: label.font.fontDescriptor, size: CGFloat(sender.value))
label.text = label.text
}
}
extension LTDemoViewController {
func morphingDidStart(_ label: LTMorphingLabel) {
}
func morphingDidComplete(_ label: LTMorphingLabel) {
}
func morphingOnProgress(_ label: LTMorphingLabel, progress: Float) {
}
}
================================================
FILE: LTMorphingLabelDemo/LTMorphingLabelDemo.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="IAM-hL-9eW">
<device id="retina4_7" orientation="landscape" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--LTMorphingLabel Demo-->
<scene sceneID="vlG-gG-Crg">
<objects>
<viewController id="3ei-2r-m0A" customClass="LTDemoViewController" customModule="Morphing" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="D5d-Wo-IoW">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="rE7-Va-JH8">
<rect key="frame" x="20" y="275" width="627" height="29"/>
<color key="backgroundColor" red="0.73333333329999995" green="0.0019310983707021894" blue="0.56318024254760291" alpha="0.69539221938775508" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="28" id="fIE-hM-Ab0"/>
<constraint firstAttribute="height" constant="28" id="vaZ-df-xh8"/>
</constraints>
<segments>
<segment title="Scale"/>
<segment title="Evaporate"/>
<segment title="Fall"/>
<segment title="Pixelate"/>
<segment title="Sparkle"/>
<segment title="Burn"/>
<segment title="Anvil"/>
</segments>
<color key="selectedSegmentTintColor" red="0.73333333329999995" green="0.0039215686269999999" blue="0.56470588239999997" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<connections>
<action selector="segmentChanged:" destination="3ei-2r-m0A" eventType="valueChanged" id="rRV-iJ-mWz"/>
</connections>
</segmentedControl>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3VJ-mH-2Xe">
<rect key="frame" x="20" y="52" width="627" height="203"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="19"/>
<state key="normal">
<color key="titleColor" red="0.73750000000000004" green="0.0" blue="0.56877266069999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="changeText:" destination="3ei-2r-m0A" eventType="touchUpInside" id="wca-7v-rZP"/>
</connections>
</button>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Ucn-av-UN6">
<rect key="frame" x="20" y="325" width="120" height="29"/>
<color key="backgroundColor" red="0.73333333329999995" green="0.0019310983710000001" blue="0.56318024249999998" alpha="0.69539221939999996" colorSpace="custom" customColorSpace="displayP3"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="9pE-1U-E4A"/>
<constraint firstAttribute="height" constant="28" id="TLk-pB-ubA"/>
</constraints>
<segments>
<segment title="Night"/>
<segment title="Day"/>
</segments>
<color key="selectedSegmentTintColor" red="0.73333333329999995" green="0.0039215686269999999" blue="0.56470588239999997" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<connections>
<action selector="toggleLight:" destination="3ei-2r-m0A" eventType="valueChanged" id="SHB-V1-FQz"/>
</connections>
</segmentedControl>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="26" minValue="9" maxValue="42" translatesAutoresizingMaskIntoConstraints="NO" id="EOd-vo-0jD">
<rect key="frame" x="168" y="323" width="477" height="31"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="uft-oC-aVu"/>
</constraints>
<color key="maximumTrackTintColor" red="0.30549782390000002" green="0.0" blue="0.2343322595" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="thumbTintColor" red="0.73414486649999999" green="0.003415785264" blue="0.56606709960000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="changeFontSize:" destination="3ei-2r-m0A" eventType="valueChanged" id="RPG-Ij-VXw"/>
</connections>
</slider>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="I'm LTMorphingLabel. Tap Me Please." textAlignment="center" lineBreakMode="tailTruncation" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fqc-dc-WVn" customClass="LTMorphingLabel" customModule="MorphingLabel">
<rect key="frame" x="20" y="52" width="627" height="203"/>
<accessibility key="accessibilityConfiguration" identifier="morphingLabel" label="morphingLabel"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="26"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<size key="shadowOffset" width="0.0" height="3"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lO7-Hn-KaX">
<rect key="frame" x="594" y="224" width="51" height="31"/>
<color key="onTintColor" red="0.61243192365132471" green="0.0" blue="0.46976621517848066" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="thumbTintColor" red="0.73414486649999999" green="0.003415785264" blue="0.56606709960000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="updateAutoStart:" destination="3ei-2r-m0A" eventType="valueChanged" id="uct-K6-Dxl"/>
</connections>
</switch>
<slider hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="0.0" maxValue="170" translatesAutoresizingMaskIntoConstraints="NO" id="SYv-GM-ZcQ">
<rect key="frame" x="18" y="224.5" width="559" height="31"/>
<color key="maximumTrackTintColor" red="0.30549782391039204" green="0.0" blue="0.23433225954000511" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="thumbTintColor" red="0.73414486646652222" green="0.003415785264223814" blue="0.56606709957122803" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="updateProgress:" destination="3ei-2r-m0A" eventType="valueChanged" id="Wq3-xc-LMd"/>
</connections>
</slider>
</subviews>
<viewLayoutGuide key="safeArea" id="upB-mu-6Xz"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.73750000000000004" green="0.0" blue="0.56877266069999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="EOd-vo-0jD" firstAttribute="top" secondItem="rE7-Va-JH8" secondAttribute="bottom" constant="20" id="7ro-9X-VKm"/>
<constraint firstItem="SYv-GM-ZcQ" firstAttribute="leading" secondItem="upB-mu-6Xz" secondAttribute="leading" constant="20" id="DbV-iG-EcM"/>
<constraint firstAttribute="trailingMargin" secondItem="EOd-vo-0jD" secondAttribute="trailing" constant="4" id="DrY-mw-8sU"/>
<constraint firstItem="fqc-dc-WVn" firstAttribute="leading" secondItem="D5d-Wo-IoW" secondAttribute="leadingMargin" id="FRI-HA-iwA"/>
<constraint firstItem="rE7-Va-JH8" firstAttribute="top" secondItem="3VJ-mH-2Xe" secondAttribute="bottom" constant="20" id="FbJ-XZ-R2b"/>
<constraint firstItem="fqc-dc-WVn" firstAttribute="top" secondItem="upB-mu-6Xz" secondAttribute="top" constant="20" id="JLl-ED-669"/>
<constraint firstItem="SYv-GM-ZcQ" firstAttribute="centerY" secondItem="lO7-Hn-KaX" secondAttribute="centerY" id="SSM-o6-i6w"/>
<constraint firstItem="EOd-vo-0jD" firstAttribute="leading" secondItem="Ucn-av-UN6" secondAttribute="trailing" constant="30" id="TpR-XE-wc6"/>
<constraint firstAttribute="trailingMargin" secondItem="rE7-Va-JH8" secondAttribute="trailing" id="URl-uL-VkH"/>
<constraint firstItem="rE7-Va-JH8" firstAttribute="leading" secondItem="D5d-Wo-IoW" secondAttribute="leadingMargin" id="Uv1-gH-Yw5"/>
<constraint firstItem="Ucn-av-UN6" firstAttribute="leading" secondItem="D5d-Wo-IoW" secondAttribute="leadingMargin" id="ato-cL-hIr"/>
<constraint firstItem="lO7-Hn-KaX" firstAttribute="leading" secondItem="SYv-GM-ZcQ" secondAttribute="trailing" constant="19" id="cYN-Mq-FvX"/>
<constraint firstItem="3VJ-mH-2Xe" firstAttribute="leading" secondItem="D5d-Wo-IoW" secondAttribute="leadingMargin" id="d9f-iq-G1D"/>
<constraint firstItem="rE7-Va-JH8" firstAttribute="top" secondItem="lO7-Hn-KaX" secondAttribute="bottom" constant="20" id="dov-c6-FLk"/>
<constraint firstItem="3VJ-mH-2Xe" firstAttribute="top" secondItem="upB-mu-6Xz" secondAttribute="top" constant="20" id="ev9-ly-VWf"/>
<constraint firstItem="upB-mu-6Xz" firstAttribute="bottom" secondItem="Ucn-av-UN6" secondAttribute="bottom" constant="22" id="fFq-dK-A0i"/>
<constraint firstItem="upB-mu-6Xz" firstAttribute="bottom" secondItem="EOd-vo-0jD" secondAttribute="bottom" constant="22" id="grd-XJ-WqJ"/>
<constraint firstItem="fqc-dc-WVn" firstAttribute="trailing" secondItem="D5d-Wo-IoW" secondAttribute="trailingMargin" id="izu-ll-ljE"/>
<constraint firstItem="rE7-Va-JH8" firstAttribute="top" secondItem="fqc-dc-WVn" secondAttribute="bottom" constant="20" id="k9Z-OZ-VrU"/>
<constraint firstItem="3VJ-mH-2Xe" firstAttribute="trailing" secondItem="D5d-Wo-IoW" secondAttribute="trailingMargin" id="o8d-0t-cq2"/>
<constraint firstItem="upB-mu-6Xz" firstAttribute="trailing" secondItem="lO7-Hn-KaX" secondAttribute="trailing" constant="24" id="oPt-lM-mnb"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="LTMorphingLabel Demo" id="A7j-8h-CTu">
<barButtonItem key="rightBarButtonItem" title="Clear" id="Bsc-Fz-3C2">
<color key="tintColor" red="1" green="0.0" blue="0.78291556679999996" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="clear:" destination="3ei-2r-m0A" id="JHT-bA-GcN"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" barStyle="black" prompted="NO"/>
<connections>
<outlet property="autoStart" destination="lO7-Hn-KaX" id="6UG-Ps-ekd"/>
<outlet property="effectSegmentControl" destination="rE7-Va-JH8" id="7jF-P0-vfe"/>
<outlet property="label" destination="fqc-dc-WVn" id="glJ-ku-ziP"/>
<outlet property="progressSlider" destination="SYv-GM-ZcQ" id="Qhe-p3-cbZ"/>
<outlet property="themeSegmentControl" destination="Ucn-av-UN6" id="n1V-0F-lBM"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="EOt-ne-B2F" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1850.824587706147" y="72.799999999999997"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="BST-oi-p39">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="IAM-hL-9eW" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" id="Cel-o5-IrA"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" translucent="NO" largeTitles="YES" id="V1l-3x-LRf">
<rect key="frame" x="0.0" y="0.0" width="667" height="32"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="barTintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" red="1" green="0.00019225223670915614" blue="0.803035042899366" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="3ei-2r-m0A" kind="relationship" relationship="rootViewController" id="Pr8-Cq-f6N"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vcq-7b-9Jx" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1851" y="-700"/>
</scene>
</scenes>
<designables>
<designable name="fqc-dc-WVn">
<size key="intrinsicContentSize" width="420" height="31"/>
</designable>
</designables>
</document>
================================================
FILE: LTMorphingLabelDemo/Launch Screen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2016 lexrus.com. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="20" y="855" width="374" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.12908115671641796" green="0.12908115671641796" blue="0.12908115671641796" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LTMorphingLabelDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="20" y="278" width="374" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.11456389925373134" green="0.11456389925373134" blue="0.11456389925373134" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
<constraint firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
================================================
FILE: LTMorphingLabelDemo.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
D701040D2516F5E500DB98F7 /* MorphingText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D764373D2467A01A0037C36B /* MorphingText.swift */; platformFilter = maccatalyst; };
D720D06B1A5E91CB00747465 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
D720D06C1A5E91CB00747465 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
D720D06D1A5E91CB00747465 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
D720D06E1A5E91CB00747465 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
D720D06F1A5E91CB00747465 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
D720D0701A5E91CB00747465 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
D720D0711A5E91CB00747465 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
D720D0721A5E91CB00747465 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
D720D0731A5E91CB00747465 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
D720D0741A5E923100747465 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
D720D0751A5E923100747465 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
D720D0761A5E923100747465 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
D720D0771A5E923100747465 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
D720D0781A5E923100747465 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
D720D0791A5E923100747465 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
D720D07A1A5E923100747465 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
D720D07B1A5E923100747465 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
D720D07C1A5E923100747465 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
D720D07D1A5E923800747465 /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
D720D07E1A5E923800747465 /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
D720D07F1A5E923800747465 /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
D720D0801A5E923800747465 /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
D72A94E01F7CAF8B007E5157 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
D72A94E11F7CAFA5007E5157 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
D73C19FA1AC2824100C1A824 /* MorphingLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; };
D73DFD021F4DB5CC00F84122 /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
D73DFD031F4DB5CC00F84122 /* LTEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC911962511C0006FA88 /* LTEasing.swift */; };
D73DFD041F4DB5CC00F84122 /* LTStringDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2C195965A00009D084 /* LTStringDiffResult.swift */; };
D73DFD051F4DB5CC00F84122 /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
D73DFD061F4DB5CC00F84122 /* LTMorphingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */; };
D73DFD071F4DB5CC00F84122 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
D73DFD081F4DB5CC00F84122 /* LTMorphingLabel+Evaporate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */; };
D73DFD091F4DB5CC00F84122 /* LTMorphingLabel+Fall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */; };
D73DFD0A1F4DB5CC00F84122 /* LTMorphingLabel+Pixelate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */; };
D73DFD0B1F4DB5CC00F84122 /* LTMorphingLabel+Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */; };
D73DFD0C1F4DB5CC00F84122 /* LTMorphingLabel+Burn.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */; };
D73DFD0D1F4DB5CC00F84122 /* LTMorphingLabel+Anvil.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */; };
D73DFD0E1F4DB5CC00F84122 /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
D73DFD111F4DB5CC00F84122 /* LTMorphingLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
D73DFD131F4DB5CC00F84122 /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
D73DFD141F4DB5CC00F84122 /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
D73DFD151F4DB5CC00F84122 /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
D73DFD161F4DB5CC00F84122 /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
D73DFD231F5056A700F84122 /* LTMorphingLabelUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */; };
D74AD974195171E7009A2ACD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AD973195171E7009A2ACD /* AppDelegate.swift */; };
D74AD976195171E7009A2ACD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D74AD975195171E7009A2ACD /* Images.xcassets */; };
D74AD98D195173B5009A2ACD /* LTMorphingLabelDemo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */; };
D7633A2B195812020009D084 /* LTDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7633A2A195812020009D084 /* LTDemoViewController.swift */; };
D7934DCB1A63AF1100AE04CE /* LTMorphingLabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */; };
D797F6F91D2E992200531960 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
D797F6FA1D2EA47A00531960 /* LTCharacterDiffResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */; };
D7D4B0241A5E87D50087F83D /* LTMorphingLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
D7D4B0381A5E87D50087F83D /* MorphingLabel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D7D4B03F1A5E8F6E0087F83D /* Fire.png in Resources */ = {isa = PBXBuildFile; fileRef = D757C31619742B1D00A34565 /* Fire.png */; };
D7D4B0401A5E8F6E0087F83D /* Sparkle.png in Resources */ = {isa = PBXBuildFile; fileRef = D723B2CB196A3FD100B1BBE8 /* Sparkle.png */; };
D7D4B0411A5E8F6E0087F83D /* Smoke.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3619750F6900902C5C /* Smoke.png */; };
D7D4B0421A5E8F6E0087F83D /* Fragment.png in Resources */ = {isa = PBXBuildFile; fileRef = D7C98F3A1975298000902C5C /* Fragment.png */; };
D7E537321B8CADF6008EF6D1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */; };
D7EF4F041AB5608000D46A0E /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
D7EF4F051AB5610200D46A0E /* LTMorphingEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */; };
D7EF4F071AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
D7EF4F081AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */; };
D7EF4F0A1AB561A400D46A0E /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
D7EF4F0B1AB561A400D46A0E /* LTEmitterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
D72A94DD1F7CAF6D007E5157 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D74AD966195171E7009A2ACD /* Project object */;
proxyType = 1;
remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
remoteInfo = LTMorphingLabel;
};
D72A94E21F7CAFAA007E5157 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D74AD966195171E7009A2ACD /* Project object */;
proxyType = 1;
remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
remoteInfo = LTMorphingLabel;
};
D73C19F81AC2823900C1A824 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D74AD966195171E7009A2ACD /* Project object */;
proxyType = 1;
remoteGlobalIDString = D7D4B01E1A5E87D50087F83D;
remoteInfo = LTMorphingLabel;
};
D73C19FB1AC28DAA00C1A824 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D74AD966195171E7009A2ACD /* Project object */;
proxyType = 1;
remoteGlobalIDString = D74AD96D195171E7009A2ACD;
remoteInfo = LTMorphingLabelDemo;
};
D73DFD251F5056A700F84122 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D74AD966195171E7009A2ACD /* Project object */;
proxyType = 1;
remoteGlobalIDString = D74AD96D195171E7009A2ACD;
remoteInfo = LTMorphingLabelDemo;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
D7D4B0371A5E87D50087F83D /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
D7D4B0381A5E87D50087F83D /* MorphingLabel.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
D723B2CB196A3FD100B1BBE8 /* Sparkle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Sparkle.png; sourceTree = "<group>"; };
D72CE5F420863C9D005BBDEF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MorphingLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D73DFD1B1F4DB5CC00F84122 /* tvOS-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "tvOS-Info.plist"; path = "/Users/lex/git/LTMorphingLabel/LTMorphingLabel/tvOS-Info.plist"; sourceTree = "<absolute>"; };
D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LTMorphingLabelUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LTMorphingLabelUITests.swift; sourceTree = "<group>"; };
D73DFD241F5056A700F84122 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D74AD96E195171E7009A2ACD /* Morphing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Morphing.app; sourceTree = BUILT_PRODUCTS_DIR; };
D74AD972195171E7009A2ACD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D74AD973195171E7009A2ACD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D74AD975195171E7009A2ACD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LTMorphingLabelDemo.storyboard; sourceTree = "<group>"; };
D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingLabel.swift; sourceTree = "<group>"; };
D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Pixelate.swift"; sourceTree = "<group>"; };
D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Burn.swift"; sourceTree = "<group>"; };
D757C31619742B1D00A34565 /* Fire.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fire.png; sourceTree = "<group>"; };
D7633A2A195812020009D084 /* LTDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTDemoViewController.swift; sourceTree = "<group>"; };
D7633A2C195965A00009D084 /* LTStringDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTStringDiffResult.swift; sourceTree = "<group>"; };
D764373D2467A01A0037C36B /* MorphingText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MorphingText.swift; sourceTree = "<group>"; };
D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LTMorphingLabelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D7934DC91A63AF1100AE04CE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LTMorphingLabelTests.swift; sourceTree = "<group>"; };
D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterDiffResult.swift; sourceTree = "<group>"; };
D7AA544125170E1100299291 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
D7AFEC911962511C0006FA88 /* LTEasing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEasing.swift; sourceTree = "<group>"; };
D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Evaporate.swift"; sourceTree = "<group>"; };
D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Fall.swift"; sourceTree = "<group>"; };
D7C98F3619750F6900902C5C /* Smoke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Smoke.png; sourceTree = "<group>"; };
D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Anvil.swift"; sourceTree = "<group>"; };
D7C98F3A1975298000902C5C /* Fragment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fragment.png; sourceTree = "<group>"; };
D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MorphingLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7D4B0221A5E87D50087F83D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LTMorphingLabel.h; sourceTree = "<group>"; };
D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Sparkle.swift"; sourceTree = "<group>"; };
D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingEffect.swift; sourceTree = "<group>"; };
D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterLimbo.swift; sourceTree = "<group>"; };
D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEmitterView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D73DFD0F1F4DB5CC00F84122 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D73DFD1D1F5056A700F84122 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D72A94E11F7CAFA5007E5157 /* MorphingLabel.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D74AD96B195171E7009A2ACD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D72A94E01F7CAF8B007E5157 /* MorphingLabel.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7934DC31A63AF1100AE04CE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D73C19FA1AC2824100C1A824 /* MorphingLabel.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7D4B01B1A5E87D50087F83D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D70FB1FB19685C3300EF9B84 /* Particles */ = {
isa = PBXGroup;
children = (
D757C31619742B1D00A34565 /* Fire.png */,
D723B2CB196A3FD100B1BBE8 /* Sparkle.png */,
D7C98F3619750F6900902C5C /* Smoke.png */,
D7C98F3A1975298000902C5C /* Fragment.png */,
);
path = Particles;
sourceTree = "<group>";
};
D72A94DF1F7CAF8B007E5157 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
D73DFD211F5056A700F84122 /* LTMorphingLabelUITests */ = {
isa = PBXGroup;
children = (
D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */,
D73DFD241F5056A700F84122 /* Info.plist */,
);
path = LTMorphingLabelUITests;
sourceTree = "<group>";
};
D74AD965195171E7009A2ACD = {
isa = PBXGroup;
children = (
D7AA544125170E1100299291 /* Package.swift */,
D72CE5F420863C9D005BBDEF /* README.md */,
D74AD98B19517201009A2ACD /* LTMorphingLabel */,
D74AD970195171E7009A2ACD /* LTMorphingLabelDemo */,
D7D4B0201A5E87D50087F83D /* LTMorphingLabel */,
D7934DC71A63AF1100AE04CE /* LTMorphingLabelTests */,
D73DFD211F5056A700F84122 /* LTMorphingLabelUITests */,
D74AD96F195171E7009A2ACD /* Products */,
D72A94DF1F7CAF8B007E5157 /* Frameworks */,
);
sourceTree = "<group>";
};
D74AD96F195171E7009A2ACD /* Products */ = {
isa = PBXGroup;
children = (
D74AD96E195171E7009A2ACD /* Morphing.app */,
D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */,
D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */,
D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */,
D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
D74AD970195171E7009A2ACD /* LTMorphingLabelDemo */ = {
isa = PBXGroup;
children = (
D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */,
D74AD973195171E7009A2ACD /* AppDelegate.swift */,
D74AD975195171E7009A2ACD /* Images.xcassets */,
D74AD971195171E7009A2ACD /* Supporting Files */,
D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */,
D7633A2A195812020009D084 /* LTDemoViewController.swift */,
);
path = LTMorphingLabelDemo;
sourceTree = "<group>";
};
D74AD971195171E7009A2ACD /* Supporting Files */ = {
isa = PBXGroup;
children = (
D74AD972195171E7009A2ACD /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
D74AD98B19517201009A2ACD /* LTMorphingLabel */ = {
isa = PBXGroup;
children = (
D7AFEC911962511C0006FA88 /* LTEasing.swift */,
D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */,
D7633A2C195965A00009D084 /* LTStringDiffResult.swift */,
D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */,
D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */,
D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */,
D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */,
D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */,
D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */,
D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */,
D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */,
D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */,
D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */,
D70FB1FB19685C3300EF9B84 /* Particles */,
D7868570246848E100D4C46F /* SwiftUI */,
);
path = LTMorphingLabel;
sourceTree = "<group>";
};
D7868570246848E100D4C46F /* SwiftUI */ = {
isa = PBXGroup;
children = (
D764373D2467A01A0037C36B /* MorphingText.swift */,
);
path = SwiftUI;
sourceTree = "<group>";
};
D7934DC71A63AF1100AE04CE /* LTMorphingLabelTests */ = {
isa = PBXGroup;
children = (
D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */,
D7934DC81A63AF1100AE04CE /* Supporting Files */,
);
path = LTMorphingLabelTests;
sourceTree = "<group>";
};
D7934DC81A63AF1100AE04CE /* Supporting Files */ = {
isa = PBXGroup;
children = (
D7934DC91A63AF1100AE04CE /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
D7D4B0201A5E87D50087F83D /* LTMorphingLabel */ = {
isa = PBXGroup;
children = (
D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */,
D7D4B0211A5E87D50087F83D /* Supporting Files */,
);
path = LTMorphingLabel;
sourceTree = "<group>";
};
D7D4B0211A5E87D50087F83D /* Supporting Files */ = {
isa = PBXGroup;
children = (
D7D4B0221A5E87D50087F83D /* Info.plist */,
D73DFD1B1F4DB5CC00F84122 /* tvOS-Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D73DFD101F4DB5CC00F84122 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D73DFD111F4DB5CC00F84122 /* LTMorphingLabel.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7D4B01C1A5E87D50087F83D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D7D4B0241A5E87D50087F83D /* LTMorphingLabel.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D73DFD001F4DB5CC00F84122 /* MorphingLabel_tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = D73DFD171F4DB5CC00F84122 /* Build configuration list for PBXNativeTarget "MorphingLabel_tvOS" */;
buildPhases = (
D73DFD011F4DB5CC00F84122 /* Sources */,
D73DFD0F1F4DB5CC00F84122 /* Frameworks */,
D73DFD101F4DB5CC00F84122 /* Headers */,
D73DFD121F4DB5CC00F84122 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MorphingLabel_tvOS;
productName = LTMorphingLabel;
productReference = D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */;
productType = "com.apple.product-type.framework";
};
D73DFD1F1F5056A700F84122 /* LTMorphingLabelUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D73DFD291F5056A700F84122 /* Build configuration list for PBXNativeTarget "LTMorphingLabelUITests" */;
buildPhases = (
D73DFD1C1F5056A700F84122 /* Sources */,
D73DFD1D1F5056A700F84122 /* Frameworks */,
D73DFD1E1F5056A700F84122 /* Resources */,
);
buildRules = (
);
dependencies = (
D73DFD261F5056A700F84122 /* PBXTargetDependency */,
D72A94E31F7CAFAA007E5157 /* PBXTargetDependency */,
);
name = LTMorphingLabelUITests;
productName = LTMorphingLabelUITests;
productReference = D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = D74AD985195171E7009A2ACD /* Build configuration list for PBXNativeTarget "LTMorphingLabelDemo" */;
buildPhases = (
D74AD96A195171E7009A2ACD /* Sources */,
D74AD96B195171E7009A2ACD /* Frameworks */,
D74AD96C195171E7009A2ACD /* Resources */,
D7D4B0371A5E87D50087F83D /* Embed Frameworks */,
D7E30A621C28449F00A708CF /* SwiftLint */,
);
buildRules = (
);
dependencies = (
D72A94DE1F7CAF6D007E5157 /* PBXTargetDependency */,
);
name = LTMorphingLabelDemo;
productName = LTMorphingLabelDemo;
productReference = D74AD96E195171E7009A2ACD /* Morphing.app */;
productType = "com.apple.product-type.application";
};
D7934DC51A63AF1100AE04CE /* LTMorphingLabelTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = D7934DD11A63AF1100AE04CE /* Build configuration list for PBXNativeTarget "LTMorphingLabelTests" */;
buildPhases = (
D7934DC21A63AF1100AE04CE /* Sources */,
D7934DC31A63AF1100AE04CE /* Frameworks */,
D7934DC41A63AF1100AE04CE /* Resources */,
);
buildRules = (
);
dependencies = (
D73C19F91AC2823900C1A824 /* PBXTargetDependency */,
D73C19FC1AC28DAA00C1A824 /* PBXTargetDependency */,
);
name = LTMorphingLabelTests;
productName = LTMorphingLabelTests;
productReference = D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D7D4B01E1A5E87D50087F83D /* MorphingLabel */ = {
isa = PBXNativeTarget;
buildConfigurationList = D7D4B03D1A5E87D50087F83D /* Build configuration list for PBXNativeTarget "MorphingLabel" */;
buildPhases = (
D7D4B01A1A5E87D50087F83D /* Sources */,
D7D4B01B1A5E87D50087F83D /* Frameworks */,
D7D4B01C1A5E87D50087F83D /* Headers */,
D7D4B01D1A5E87D50087F83D /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = MorphingLabel;
productName = LTMorphingLabel;
productReference = D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D74AD966195171E7009A2ACD /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftMigration = 0700;
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 1240;
ORGANIZATIONNAME = lexrus.com;
TargetAttributes = {
D73DFD1F1F5056A700F84122 = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = 5SKD83S59G;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
TestTargetID = D74AD96D195171E7009A2ACD;
};
D74AD96D195171E7009A2ACD = {
CreatedOnToolsVersion = 6.0;
LastSwiftMigration = 1020;
};
D7934DC51A63AF1100AE04CE = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 1020;
TestTargetID = D74AD96D195171E7009A2ACD;
};
D7D4B01E1A5E87D50087F83D = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 1020;
};
};
};
buildConfigurationList = D74AD969195171E7009A2ACD /* Build configuration list for PBXProject "LTMorphingLabelDemo" */;
compatibilityVersion = "Xcode 6.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D74AD965195171E7009A2ACD;
productRefGroup = D74AD96F195171E7009A2ACD /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */,
D7D4B01E1A5E87D50087F83D /* MorphingLabel */,
D7934DC51A63AF1100AE04CE /* LTMorphingLabelTests */,
D73DFD001F4DB5CC00F84122 /* MorphingLabel_tvOS */,
D73DFD1F1F5056A700F84122 /* LTMorphingLabelUITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D73DFD121F4DB5CC00F84122 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D73DFD131F4DB5CC00F84122 /* Fire.png in Resources */,
D73DFD141F4DB5CC00F84122 /* Sparkle.png in Resources */,
D73DFD151F4DB5CC00F84122 /* Smoke.png in Resources */,
D73DFD161F4DB5CC00F84122 /* Fragment.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D73DFD1E1F5056A700F84122 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D74AD96C195171E7009A2ACD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D720D07D1A5E923800747465 /* Fire.png in Resources */,
D720D07E1A5E923800747465 /* Sparkle.png in Resources */,
D720D07F1A5E923800747465 /* Smoke.png in Resources */,
D720D0801A5E923800747465 /* Fragment.png in Resources */,
D74AD98D195173B5009A2ACD /* LTMorphingLabelDemo.storyboard in Resources */,
D74AD976195171E7009A2ACD /* Images.xcassets in Resources */,
D7E537321B8CADF6008EF6D1 /* Launch Screen.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7934DC41A63AF1100AE04CE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
D7D4B01D1A5E87D50087F83D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D7D4B03F1A5E8F6E0087F83D /* Fire.png in Resources */,
D7D4B0401A5E8F6E0087F83D /* Sparkle.png in Resources */,
D7D4B0411A5E8F6E0087F83D /* Smoke.png in Resources */,
D7D4B0421A5E8F6E0087F83D /* Fragment.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
D7E30A621C28449F00A708CF /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftLint;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"SwiftLint does not exist, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D73DFD011F4DB5CC00F84122 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D73DFD021F4DB5CC00F84122 /* LTCharacterLimbo.swift in Sources */,
D73DFD031F4DB5CC00F84122 /* LTEasing.swift in Sources */,
D73DFD041F4DB5CC00F84122 /* LTStringDiffResult.swift in Sources */,
D73DFD051F4DB5CC00F84122 /* LTMorphingEffect.swift in Sources */,
D73DFD061F4DB5CC00F84122 /* LTMorphingLabel.swift in Sources */,
D73DFD071F4DB5CC00F84122 /* LTCharacterDiffResult.swift in Sources */,
D73DFD081F4DB5CC00F84122 /* LTMorphingLabel+Evaporate.swift in Sources */,
D73DFD091F4DB5CC00F84122 /* LTMorphingLabel+Fall.swift in Sources */,
D73DFD0A1F4DB5CC00F84122 /* LTMorphingLabel+Pixelate.swift in Sources */,
D73DFD0B1F4DB5CC00F84122 /* LTMorphingLabel+Sparkle.swift in Sources */,
D73DFD0C1F4DB5CC00F84122 /* LTMorphingLabel+Burn.swift in Sources */,
D73DFD0D1F4DB5CC00F84122 /* LTMorphingLabel+Anvil.swift in Sources */,
D73DFD0E1F4DB5CC00F84122 /* LTEmitterView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D73DFD1C1F5056A700F84122 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D73DFD231F5056A700F84122 /* LTMorphingLabelUITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D74AD96A195171E7009A2ACD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D720D0741A5E923100747465 /* LTEasing.swift in Sources */,
D7EF4F071AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */,
D720D0751A5E923100747465 /* LTStringDiffResult.swift in Sources */,
D7EF4F051AB5610200D46A0E /* LTMorphingEffect.swift in Sources */,
D720D0761A5E923100747465 /* LTMorphingLabel.swift in Sources */,
D720D0771A5E923100747465 /* LTMorphingLabel+Evaporate.swift in Sources */,
D720D0781A5E923100747465 /* LTMorphingLabel+Fall.swift in Sources */,
D720D0791A5E923100747465 /* LTMorphingLabel+Pixelate.swift in Sources */,
D720D07A1A5E923100747465 /* LTMorphingLabel+Sparkle.swift in Sources */,
D720D07B1A5E923100747465 /* LTMorphingLabel+Burn.swift in Sources */,
D720D07C1A5E923100747465 /* LTMorphingLabel+Anvil.swift in Sources */,
D7EF4F0A1AB561A400D46A0E /* LTEmitterView.swift in Sources */,
D74AD974195171E7009A2ACD /* AppDelegate.swift in Sources */,
D797F6FA1D2EA47A00531960 /* LTCharacterDiffResult.swift in Sources */,
D7633A2B195812020009D084 /* LTDemoViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7934DC21A63AF1100AE04CE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D7934DCB1A63AF1100AE04CE /* LTMorphingLabelTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D7D4B01A1A5E87D50087F83D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D701040D2516F5E500DB98F7 /* MorphingText.swift in Sources */,
D7EF4F081AB5612C00D46A0E /* LTCharacterLimbo.swift in Sources */,
D720D06B1A5E91CB00747465 /* LTEasing.swift in Sources */,
D720D06C1A5E91CB00747465 /* LTStringDiffResult.swift in Sources */,
D7EF4F041AB5608000D46A0E /* LTMorphingEffect.swift in Sources */,
D720D06D1A5E91CB00747465 /* LTMorphingLabel.swift in Sources */,
D797F6F91D2E992200531960 /* LTCharacterDiffResult.swift in Sources */,
D720D06E1A5E91CB00747465 /* LTMorphingLabel+Evaporate.swift in Sources */,
D720D06F1A5E91CB00747465 /* LTMorphingLabel+Fall.swift in Sources */,
D720D0701A5E91CB00747465 /* LTMorphingLabel+Pixelate.swift in Sources */,
D720D0711A5E91CB00747465 /* LTMorphingLabel+Sparkle.swift in Sources */,
D720D0721A5E91CB00747465 /* LTMorphingLabel+Burn.swift in Sources */,
D720D0731A5E91CB00747465 /* LTMorphingLabel+Anvil.swift in Sources */,
D7EF4F0B1AB561A400D46A0E /* LTEmitterView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
D72A94DE1F7CAF6D007E5157 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
targetProxy = D72A94DD1F7CAF6D007E5157 /* PBXContainerItemProxy */;
};
D72A94E31F7CAFAA007E5157 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
targetProxy = D72A94E21F7CAFAA007E5157 /* PBXContainerItemProxy */;
};
D73C19F91AC2823900C1A824 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D7D4B01E1A5E87D50087F83D /* MorphingLabel */;
targetProxy = D73C19F81AC2823900C1A824 /* PBXContainerItemProxy */;
};
D73C19FC1AC28DAA00C1A824 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */;
targetProxy = D73C19FB1AC28DAA00C1A824 /* PBXContainerItemProxy */;
};
D73DFD261F5056A700F84122 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D74AD96D195171E7009A2ACD /* LTMorphingLabelDemo */;
targetProxy = D73DFD251F5056A700F84122 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
D73DFD181F4DB5CC00F84122 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "$(SRCROOT)/LTMorphingLabel/tvOS-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
PRODUCT_NAME = MorphingLabel;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2,3";
TVOS_DEPLOYMENT_TARGET = 12.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D73DFD191F4DB5CC00F84122 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "$(SRCROOT)/LTMorphingLabel/tvOS-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
PRODUCT_NAME = MorphingLabel;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2,3";
TVOS_DEPLOYMENT_TARGET = 12.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
D73DFD271F5056A700F84122 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 5SKD83S59G;
INFOPLIST_FILE = LTMorphingLabelUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.LexTang.LTMorphingLabelUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
TEST_TARGET_NAME = LTMorphingLabelDemo;
};
name = Debug;
};
D73DFD281F5056A700F84122 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 5SKD83S59G;
INFOPLIST_FILE = LTMorphingLabelUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.LexTang.LTMorphingLabelUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_TARGET_NAME = LTMorphingLabelDemo;
};
name = Release;
};
D74AD983195171E7009A2ACD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
METAL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
D74AD984195171E7009A2ACD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
METAL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D74AD986195171E7009A2ACD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 5SKD83S59G;
INFOPLIST_FILE = LTMorphingLabelDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabelDemo;
PRODUCT_NAME = Morphing;
PROVISIONING_PROFILE = "";
SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
D74AD987195171E7009A2ACD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 5SKD83S59G;
INFOPLIST_FILE = LTMorphingLabelDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabelDemo;
PRODUCT_NAME = Morphing;
PROVISIONING_PROFILE = "";
SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = "";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
D7934DCF1A63AF1100AE04CE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = LTMorphingLabelTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.LexTang.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LTMorphingLabelDemo.app/LTMorphingLabelDemo";
};
name = Debug;
};
D7934DD01A63AF1100AE04CE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = LTMorphingLabelTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.LexTang.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LTMorphingLabelDemo.app/LTMorphingLabelDemo";
};
name = Release;
};
D7D4B0391A5E87D50087F83D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = LTMorphingLabel/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
PRODUCT_NAME = MorphingLabel;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D7D4B03A1A5E87D50087F83D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = LTMorphingLabel/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = sh.lex.LTMorphingLabel;
PRODUCT_NAME = MorphingLabel;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D73DFD171F4DB5CC00F84122 /* Build configuration list for PBXNativeTarget "MorphingLabel_tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D73DFD181F4DB5CC00F84122 /* Debug */,
D73DFD191F4DB5CC00F84122 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D73DFD291F5056A700F84122 /* Build configuration list for PBXNativeTarget "LTMorphingLabelUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D73DFD271F5056A700F84122 /* Debug */,
D73DFD281F5056A700F84122 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D74AD969195171E7009A2ACD /* Build configuration list for PBXProject "LTMorphingLabelDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D74AD983195171E7009A2ACD /* Debug */,
D74AD984195171E7009A2ACD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D74AD985195171E7009A2ACD /* Build configuration list for PBXNativeTarget "LTMorphingLabelDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D74AD986195171E7009A2ACD /* Debug */,
D74AD987195171E7009A2ACD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D7934DD11A63AF1100AE04CE /* Build configuration list for PBXNativeTarget "LTMorphingLabelTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D7934DCF1A63AF1100AE04CE /* Debug */,
D7934DD01A63AF1100AE04CE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D7D4B03D1A5E87D50087F83D /* Build configuration list for PBXNativeTarget "MorphingLabel" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D7D4B0391A5E87D50087F83D /* Debug */,
D7D4B03A1A5E87D50087F83D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D74AD966195171E7009A2ACD /* Project object */;
}
================================================
FILE: LTMorphingLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/lex/git/LTMorphingLabel/LTMorphingLabelDemo.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/LTMorphingLabelDemo.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D74AD96D195171E7009A2ACD"
BuildableName = "Morphing.app"
BlueprintName = "LTMorphingLabelDemo"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D74AD96D195171E7009A2ACD"
BuildableName = "Morphing.app"
BlueprintName = "LTMorphingLabelDemo"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D7934DC51A63AF1100AE04CE"
BuildableName = "LTMorphingLabelTests.xctest"
BlueprintName = "LTMorphingLabelTests"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D73DFD1F1F5056A700F84122"
BuildableName = "LTMorphingLabelUITests.xctest"
BlueprintName = "LTMorphingLabelUITests"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D74AD96D195171E7009A2ACD"
BuildableName = "Morphing.app"
BlueprintName = "LTMorphingLabelDemo"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D74AD96D195171E7009A2ACD"
BuildableName = "Morphing.app"
BlueprintName = "LTMorphingLabelDemo"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/MorphingLabel.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D7D4B01E1A5E87D50087F83D"
BuildableName = "MorphingLabel.framework"
BlueprintName = "MorphingLabel"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D7D4B01E1A5E87D50087F83D"
BuildableName = "MorphingLabel.framework"
BlueprintName = "MorphingLabel"
ReferencedContainer = "container:LTMorphingLabelDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: LTMorphingLabelTests/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: LTMorphingLabelTests/LTMorphingLabelTests.swift
================================================
//
// LTMorphingLabelTests.swift
// LTMorphingLabelTests
//
// Created by Lex Tang on 1/12/15.
// Copyright (c) 2015 lexrus.com. All rights reserved.
//
import XCTest
import MorphingLabel
class LTMorphingLabelTests : XCTestCase {
func testStringDiff1() {
let diffResults = "he".diffWith("hello")
XCTAssert(
diffResults.0[0] == .same,
"First character isn't changed."
)
XCTAssert(diffResults.0[2] == .add, "Third character is added.")
}
func testStringDiff2() {
let diffResults = "news".diffWith("westen")
if case .moveAndAdd(let offset) = diffResults.0[0] {
XCTAssert(
offset == 5,
"n is moved right for 5 steps, not \(offset)."
)
} else {
XCTFail("Failed to move and add.")
}
if case .moveAndAdd(let offset) = diffResults.0[2] {
XCTAssert(
offset == -2,
"w is moved left for 2 steps, not \(offset)."
)
} else {
XCTFail("Failed to move and add.")
}
XCTAssert(diffResults.0[4] == .add, "2nd e is added.")
XCTAssert(diffResults.1[5], "The last n was moved in.")
}
func testStringDiff3() {
let diffResults = "Enchanté".diffWith("Swifter")
XCTAssert(diffResults.0[4] == .replace, "a is deleted.")
}
func testStringDiff4() {
let diffResults = "wo".diffWith("ox")
XCTAssert(diffResults.0[0] == .replace, "w is replaced.")
XCTAssert(
diffResults.0[1] == .moveAndAdd(offset: -1),
"o is moved and add a new character."
)
}
func testStringDiff5() {
let diffResults = "Objective-C".diffWith("iPhone")
XCTAssert(diffResults.0[0] == .replace, "w is replaced.")
XCTAssert(
diffResults.0[3] == .moveAndAdd(offset: 2),
"e is moved and add a new character."
)
XCTAssert(diffResults.0[8] == .delete, "2nd e is deleted.")
}
func testStringDiff6() {
let diffResults = "wow".diffWith("newwow")
XCTAssert(diffResults.0[2] == .moveAndAdd(offset: 1), "2nd. w is moved.")
}
func testEmojiDiff7() {
let diffResults = "1️⃣2️⃣3️⃣".diffWith("3️⃣1️⃣2️⃣")
XCTAssert(diffResults.0[0] == .moveAndAdd(offset: 1), "1st. 1 is moved.")
}
func testEmptyDiff8() {
let diffResults0 = "".diffWith("hello")
XCTAssert(diffResults0.0[0] == .add, "Every characters must be added.")
let diffResults1 = "".diffWith("")
XCTAssert(diffResults1.0.count == 0, "Must be empty.")
let diffResults2 = "Hello".diffWith("")
XCTAssert(diffResults2.0[0] == .delete, "Must be empty.")
}
func testLongDiffPerformance() {
measure {
let lhs =
"Design is not just what it looks like and feels like."
+ "Design is how it works."
let rhs =
"Innovation distinguishes between a leader and a follower."
_ = lhs.diffWith(rhs)
}
}
}
================================================
FILE: LTMorphingLabelUITests/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: LTMorphingLabelUITests/LTMorphingLabelUITests.swift
================================================
//
// LTMorphingLabelUITests.swift
// LTMorphingLabelUITests
//
// Created by Lex on 25/08/2017.
// Copyright © 2017 lexrus.com. All rights reserved.
//
import XCTest
import MorphingLabel
class LTMorphingLabelUITests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
XCUIApplication().launch()
}
override func tearDown() {
super.tearDown()
}
func testMonkeyTest() {
let app = XCUIApplication()
app.buttons["Evaporate"].tap()
app.buttons["Fall"].tap()
let morphinglabelStaticText = XCUIApplication().staticTexts["morphingLabel"]
for _ in 0...20 {
morphinglabelStaticText.tap()
}
}
func testNilText() {
let app = XCUIApplication()
app.buttons["Clear"].tap()
let label = app.staticTexts["morphingLabel"]
guard label.exists else {
XCTFail("must have a morphingLabel with accessibilityIdentifier 'morphingLabel'")
return
}
app.buttons["Scale"].tap()
}
}
================================================
FILE: Package.swift
================================================
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "MorphingLabel",
products: [
.library(name: "MorphingLabel", targets: ["MorphingLabel"]),
.library(name: "MorphingLabelDynamic", type: .dynamic, targets: ["MorphingLabel"]),
.library(name: "MorphinglabelXCFramework", targets: ["LTMorphingLabel"])
],
targets: [
.target(
name: "MorphingLabel",
exclude: [
"Info.plist",
"tvOS-Info.plist"
],
resources: [
.process("Particles")
]
),
.binaryTarget(
name: "LTMorphingLabel",
url: "https://github.com/lexrus/LTMorphingLabel/releases/download/0.9.3/LTMorphingLabel.xcframework.zip",
checksum: "28a0ed8b7df12c763d45b7dde2aa41fd843984b79e6fbd3750f2fc1a6c247a13"
)
]
)
================================================
FILE: README.md
================================================
# LTMorphingLabel

[](https://github.com/lexrus/LTMorphingLabel)
[](https://github.com/Carthage/Carthage)
[](https://github.com/JamitLabs/Accio)

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).
## Table of Contents
- [Available Effects](#available-effects)
- [.scale](#scale-default)
- [.evaporate](#evaporate)
- [.fall](#fall)
- [.pixelate](#pixelate)
- [.sparkle](#sparkle)
- [.burn](#burn)
- [Usage](#usage)
- [UIKit](#uikit)
- [SwiftUI](#swiftui)
- [Requirements](#requirements)
- [Installation](#installation)
- [Swift Package Manager](#swift-package-manager)
- [CocoaPods](#cocoapods)
- [Carthage](#carthage)
- [XCFramework](#xcframework)
- [Accio](#accio)
- [Unit Testing](#unit-testing)
- [Apps Using `LTMorphingLabel`](#apps-using-ltmorphinglabel)
- [Third-Party Ports](#third-party-ports)
- [Android](#android)
- [React Native](#react-native)
- [License](#license)
## Available Effects
#### .scale (_default_)
<img src="https://cloud.githubusercontent.com/assets/219689/3491822/96bf5de6-059d-11e4-9826-a6f82025d1af.gif" width="300" height="70" alt="LTMorphingLabel"/>
#### [.evaporate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BEvaporate.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3491838/ffc5aff2-059d-11e4-970c-6e2d7664785a.gif" width="300" height="70" alt="LTMorphingLabel-Evaporate"/>
#### [.fall](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BFall.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3491840/173c2238-059e-11e4-9b33-dcd21edae9e2.gif" width="300" height="70" alt="LTMorphingLabel-Fall"/>
#### [.pixelate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BPixelate.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3491845/29bb0f8c-059e-11e4-9ef8-de56bec1baba.gif" width="300" height="70" alt="LTMorphingLabel-Pixelate"/>
#### [.sparkle](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BSparkle.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3508789/31e9fafe-0690-11e4-9a76-ba3ef45eb53a.gif" width="300" height="70" alt="LTMorphingLabel-Sparkle"/>
> `.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).
#### [.burn](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BBurn.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3582586/4fb8c52e-0bfe-11e4-9b6f-f070f7f3ab55.gif" width="300" height="70" alt="LTMorphingLabel-Burn"/>
#### [.anvil](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BAnvil.swift)
<img src="https://cloud.githubusercontent.com/assets/219689/3594949/815cd3e8-0caa-11e4-9738-278a9c959478.gif" width="300" height="70" alt="LTMorphingLabel-Anvil"/>
## Usage
### UIKit
Since `LTMorphingLabel` is a drop-in replacement, you can use it like any `UILabel` by setting its text property, yielding the default effect (`.scale`):
```swift
var exampleLabel = LTMorphingLabel()
exampleLabel.text = "This is a test"
```

Alternatively, it can be used interactively:
```swift
var exampleLabel = LTMorphingLabel()
exampleLabel.text = "This is a test"
exampleLabel.pause()
// Call .updateProgress(progress: Float) for interactive animation
// Note: In this case, animation will stop at 45% and will not complete
// unless called later with 100 as the `progress` float value.
exampleLabel.updateProgress(progress: 45.0)
```
The effect can be changed by setting the `morphingEffect` property:
```swift
var exampleLabel = LTMorphingLabel()
exampleLabel.text = "This is a test"
exampleLabel.morphingEffect = .burn
```

### SwiftUI
To use `LTMorphingLabel` in SwiftUI, simply declare it and set its text, `effect`, `font`, and `textColor` properties:
```swift
public var body: some View {
VStack {
MorphingText(
"This is a test",
font: UIFont.systemFont(ofSize: 20),
textColor: .black,
textAlignment: .center
)
.frame(maxWidth: 200, maxHeight: 100)
}
}
```
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):
```swift
public var body: some View {
VStack {
MorphingText(
"This is a test",
effect: .burn, // Specify an alternative morphing effect with this line
font: UIFont.systemFont(ofSize: 20),
textColor: .black,
textAlignment: .center
)
.frame(maxWidth: 200, maxHeight: 100)
}
}
```

## Requirements
- Xcode 12+
- iOS 9.0+ (note that SwiftUI requires iOS 13+)
## Installation
### [Swift Package Manager](https://swift.org/package-manager/)
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).
```swift
.package(
url: "https://github.com/lexrus/LTMorphingLabel.git",
.branch("master")
)
```
### [CocoaPods](http://cocoapods.org)
Add `pod 'LTMorphingLabel'` to your Podfile or follow instructions to add dependencies [here](https://guides.cocoapods.org/using/using-cocoapods.html).
### [Carthage](https://github.com/Carthage/Carthage)
Add `github "lexrus/LTMorphingLabel"` to your Cartfile or follow instructions on adding frameworks [here](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
### [XCFramework](https://developer.apple.com/videos/play/wwdc2019/416/)
A pre-compiled `xcframework` file is available on the [Releases](https://github.com/lexrus/LTMorphingLabel/releases) page.
### [Accio](https://github.com/JamitLabs/Accio)
1. Add this library to your package manifest (see [Swift Package Manager](#swift-package-manager))
2. Update your target dependencies to include `LTMorphingLabel`:
```swift
.target(
name: "App",
dependencies: [
"LTMorphingLabel",
]
),
```
3. Run `accio update`.
## Unit Testing
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).
## Apps Using `LTMorphingLabel`
- [Idea](https://itunes.apple.com/app/id1286758943) by [Igor Matyushkin](https://github.com/igormatyushkin014)
- [Speedo[kilo]meter](https://itunes.apple.com/it/app/speedo-kilo-meter/id1228840413?mt=8) by [Alberto Pasca](http://www.albertopasca.it/whiletrue)
- [The Met Challenge](https://itunes.apple.com/us/app/the-met-challenge/id917662781) by [@lazerwalker](https://github.com/lazerwalker)
- [Uther](https://github.com/callmewhy/Uther) by [@callmewhy](https://github.com/callmewhy)
- [Reax](https://itunes.apple.com/us/app/reax-witness-2016-here.-now./id1076183758?ls=1&mt=8) by Reax Inc
- [Puzzpic](https://itunes.apple.com/us/app/puzzpic/id1092871121) by [Moath Othman](http://moathothman.com)
- [Drops](http://languagedrops.com) by [Mark Aron Szulyovszky](https://github.com/itchingpixels)
- [Setgraph Workout Log](https://itunes.apple.com/us/app/setgraph-workout-log/id1209781676?mt=8) by [Arturo Lee](https://github.com/ArturoLee)
- [Nihon](https://itunes.apple.com/app/id1315486029) by [KyXu](https://github.com/OpenMarshall)
- [Lightsync](https://itunes.apple.com/app/id1463390406?mt=8&ct=ghltml) by [Marcel Braun](https://github.com/thatmarcel)
- [Find](https://apps.apple.com/app/find-command-f-for-camera/id1506500202) by [A. Zheng](https://github.com/aheze)
## Third-Party Ports
### Android
The Android port of this library is available [here](https://github.com/hanks-zyh/HTextView).
### React Native
The React Native port of this library is available [here](https://github.com/prscX/react-native-morphing-text).
## License
This code is distributed under the terms and conditions of the MIT license.
================================================
FILE: build_xcframework.sh
================================================
#!/bin/bash
PROJECT_FILE="LTMorphingLabelDemo.xcodeproj"
SCHEME="MorphingLabel"
BUILD_FOLDER="Build/MorphingLabel"
mkdir -p Build
# iOS Simulator
xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
-archivePath "$BUILD_FOLDER/Simulator" \
-sdk iphonesimulator \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# iOS
xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
-archivePath "$BUILD_FOLDER/iOS" \
-sdk iphoneos \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# tvOS
xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
-archivePath "$BUILD_FOLDER/tvOS" \
-sdk appletvos \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# tvOS Simulator
xcodebuild archive -project "$PROJECT_FILE" -scheme "$SCHEME" -configuration Release \
-archivePath "$BUILD_FOLDER/tvOSSimulator" \
-sdk appletvsimulator \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# XCFramework
xcodebuild -create-xcframework \
-framework "$BUILD_FOLDER/iOS.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
-framework "$BUILD_FOLDER/tvOS.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
-framework "$BUILD_FOLDER/Simulator.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
-framework "$BUILD_FOLDER/tvOSSimulator.xcarchive/Products/Library/Frameworks/MorphingLabel.framework" \
-output Build/LTMorphingLabel.xcframework
cd Build
# Compress
zip -vry LTMorphingLabel.xcframework.zip LTMorphingLabel.xcframework/ -x "*.DS_Store"
# Checksum for Package.swift
swift package compute-checksum LTMorphingLabel.xcframework.zip
# Open in Finder
open ./
gitextract_90kd__s2/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .swiftlint.yml ├── LICENSE ├── 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 │ ├── SwiftUI/ │ │ └── MorphingText.swift │ └── tvOS-Info.plist ├── LTMorphingLabel.podspec ├── LTMorphingLabelDemo/ │ ├── AppDelegate.swift │ ├── Images.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── LTDemoViewController.swift │ ├── LTMorphingLabelDemo.storyboard │ └── Launch Screen.storyboard ├── LTMorphingLabelDemo.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata/ │ └── xcschemes/ │ ├── LTMorphingLabelDemo.xcscheme │ └── MorphingLabel.xcscheme ├── LTMorphingLabelTests/ │ ├── Info.plist │ └── LTMorphingLabelTests.swift ├── LTMorphingLabelUITests/ │ ├── Info.plist │ └── LTMorphingLabelUITests.swift ├── Package.swift ├── README.md └── build_xcframework.sh
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (207K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 678,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
},
{
"path": ".gitignore",
"chars": 1811,
"preview": "\n# Created by https://www.gitignore.io/api/osx,carthage,swift\n\n### Carthage ###\n# Carthage\n#\n# Add this line if you want"
},
{
"path": ".swiftlint.yml",
"chars": 299,
"preview": "disabled_rules:\n - todo\n - force_cast\n - trailing_whitespace\n - colon\n - identifier_name\n - type_name\n - comma\n "
},
{
"path": "LICENSE",
"chars": 1088,
"preview": "The MIT License (MIT)\nCopyright © 2026 Lex Tang, https://lex.sh\n\nPermission is hereby granted, free of charge, to any pe"
},
{
"path": "LTMorphingLabel/Info.plist",
"chars": 806,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabel/LTCharacterDiffResult.swift",
"chars": 2628,
"preview": "//\n// LTCharacterDiffResult.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyri"
},
{
"path": "LTMorphingLabel/LTCharacterLimbo.swift",
"chars": 1788,
"preview": "//\n// LTCharacterLimbo.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyright ("
},
{
"path": "LTMorphingLabel/LTEasing.swift",
"chars": 1607,
"preview": "//\n// LTEasing.swift\n// LTMorphingLabelDemo\n//\n// Created by Lex on 7/1/14.\n// Copyright (c) 2015 lexrus.com. All ri"
},
{
"path": "LTMorphingLabel/LTEmitterView.swift",
"chars": 4873,
"preview": "//\n// LTEmitterView.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyright (c) "
},
{
"path": "LTMorphingLabel/LTMorphingEffect.swift",
"chars": 2732,
"preview": "//\n// LTMorphingEffect.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyright ("
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Anvil.swift",
"chars": 11234,
"preview": "//\n// LTMorphingLabel+Anvil.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyri"
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Burn.swift",
"chars": 8061,
"preview": "//\n// LTMorphingLabel+Burn.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyrig"
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Evaporate.swift",
"chars": 3016,
"preview": "//\n// LTMorphingLabel+Evaporate.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Co"
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Fall.swift",
"chars": 5724,
"preview": "//\n// LTMorphingLabel+Fall.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyrig"
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Pixelate.swift",
"chars": 3681,
"preview": "//\n// LTMorphingLabel+Pixelate.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Cop"
},
{
"path": "LTMorphingLabel/LTMorphingLabel+Sparkle.swift",
"chars": 6083,
"preview": "//\n// LTMorphingLabel+Sparkle.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copy"
},
{
"path": "LTMorphingLabel/LTMorphingLabel.h",
"chars": 534,
"preview": "//\n// LTMorphingLabel.h\n// LTMorphingLabel\n//\n// Created by Lex Tang on 1/8/15.\n// Copyright (c) 2015 lexrus.com. Al"
},
{
"path": "LTMorphingLabel/LTMorphingLabel.swift",
"chars": 17883,
"preview": "//\n// LTMorphingLabel.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyright (c"
},
{
"path": "LTMorphingLabel/LTStringDiffResult.swift",
"chars": 3864,
"preview": "//\n// LTStringDiffResult.swift\n// https://github.com/lexrus/LTMorphingLabel\n//\n// The MIT License (MIT)\n// Copyright"
},
{
"path": "LTMorphingLabel/SwiftUI/MorphingText.swift",
"chars": 3553,
"preview": "//\n// MorphingText.swift\n// LTMorphingLabel\n//\n// Created by Lex on 2020/5/10.\n// Copyright © 2020 lexrus.com. All r"
},
{
"path": "LTMorphingLabel/tvOS-Info.plist",
"chars": 806,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabel.podspec",
"chars": 1899,
"preview": "Pod::Spec.new do |s|\n\n s.name = \"LTMorphingLabel\"\n s.version = \"0.9.3\"\n s.summary = \"Graceful morph"
},
{
"path": "LTMorphingLabelDemo/AppDelegate.swift",
"chars": 586,
"preview": "//\n// AppDelegate.swift\n// LTMorphingLabelDemo\n//\n// Created by Lex on 6/18/14.\n// Copyright (c) 2015 lexrus.com. Al"
},
{
"path": "LTMorphingLabelDemo/Images.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1774,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "LTMorphingLabelDemo/Images.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "LTMorphingLabelDemo/Info.plist",
"chars": 1387,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabelDemo/LTDemoViewController.swift",
"chars": 3304,
"preview": "//\n// LTDemoViewController.swift\n// LTMorphingLabelDemo\n//\n// Created by Lex on 6/23/14.\n// Copyright (c) 2015 lexru"
},
{
"path": "LTMorphingLabelDemo/LTMorphingLabelDemo.storyboard",
"chars": 18015,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "LTMorphingLabelDemo/Launch Screen.storyboard",
"chars": 4693,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "LTMorphingLabelDemo.xcodeproj/project.pbxproj",
"chars": 54010,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 52;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "LTMorphingLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 195,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:/Users/lex/git/"
},
{
"path": "LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/LTMorphingLabelDemo.xcscheme",
"chars": 4217,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1240\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/MorphingLabel.xcscheme",
"chars": 2429,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1240\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "LTMorphingLabelTests/Info.plist",
"chars": 733,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabelTests/LTMorphingLabelTests.swift",
"chars": 3189,
"preview": "//\n// LTMorphingLabelTests.swift\n// LTMorphingLabelTests\n//\n// Created by Lex Tang on 1/12/15.\n// Copyright (c) 2015"
},
{
"path": "LTMorphingLabelUITests/Info.plist",
"chars": 680,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LTMorphingLabelUITests/LTMorphingLabelUITests.swift",
"chars": 1121,
"preview": "//\n// LTMorphingLabelUITests.swift\n// LTMorphingLabelUITests\n//\n// Created by Lex on 25/08/2017.\n// Copyright © 2017"
},
{
"path": "Package.swift",
"chars": 911,
"preview": "// swift-tools-version:5.3\nimport PackageDescription\n\nlet package = Package(\n name: \"MorphingLabel\",\n products: [\n"
},
{
"path": "README.md",
"chars": 9053,
"preview": "# LTMorphingLabel\n\n\n[. The extraction includes 41 files (188.4 KB), approximately 53.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.