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 ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ 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 < (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l < r case (nil, _?): return true default: return false } } private func > (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 //! 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 ================================================ 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 < (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l < r case (nil, _?): return true default: return false } } private func >= (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.. 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 ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ 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 ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName $(PRODUCT_NAME) CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS NSMainNibFile~ipad LTMorphingLabelDemo-iPad UILaunchStoryboardName Launch Screen UIMainStoryboardFile LTMorphingLabelDemo UIRequiredDeviceCapabilities armv7 UIStatusBarStyle UIStatusBarStyleLightContent UISupportedInterfaceOrientations UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ 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 ================================================ ================================================ FILE: LTMorphingLabelDemo/Launch Screen.storyboard ================================================ ================================================ 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 = ""; }; D72CE5F420863C9D005BBDEF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; D73DFD241F5056A700F84122 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 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 = ""; }; D74AD973195171E7009A2ACD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; D74AD975195171E7009A2ACD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; D74AD98C195173B5009A2ACD /* LTMorphingLabelDemo.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LTMorphingLabelDemo.storyboard; sourceTree = ""; }; D74AD98E19517430009A2ACD /* LTMorphingLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingLabel.swift; sourceTree = ""; }; D7558D391962AB3000DCF592 /* LTMorphingLabel+Pixelate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Pixelate.swift"; sourceTree = ""; }; D757C30C1974243400A34565 /* LTMorphingLabel+Burn.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Burn.swift"; sourceTree = ""; }; D757C31619742B1D00A34565 /* Fire.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fire.png; sourceTree = ""; }; D7633A2A195812020009D084 /* LTDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTDemoViewController.swift; sourceTree = ""; }; D7633A2C195965A00009D084 /* LTStringDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTStringDiffResult.swift; sourceTree = ""; }; D764373D2467A01A0037C36B /* MorphingText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MorphingText.swift; sourceTree = ""; }; 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 = ""; }; D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LTMorphingLabelTests.swift; sourceTree = ""; }; D797F6F81D2E992200531960 /* LTCharacterDiffResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterDiffResult.swift; sourceTree = ""; }; D7AA544125170E1100299291 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; D7AFEC911962511C0006FA88 /* LTEasing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEasing.swift; sourceTree = ""; }; D7AFEC93196256720006FA88 /* LTMorphingLabel+Evaporate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Evaporate.swift"; sourceTree = ""; }; D7AFEC97196280860006FA88 /* LTMorphingLabel+Fall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Fall.swift"; sourceTree = ""; }; D7C98F3619750F6900902C5C /* Smoke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Smoke.png; sourceTree = ""; }; D7C98F381975265C00902C5C /* LTMorphingLabel+Anvil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Anvil.swift"; sourceTree = ""; }; D7C98F3A1975298000902C5C /* Fragment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Fragment.png; sourceTree = ""; }; 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 = ""; }; D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LTMorphingLabel.h; sourceTree = ""; }; D7E537311B8CADF6008EF6D1 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; D7EC5FD5196692E8004E7076 /* LTMorphingLabel+Sparkle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LTMorphingLabel+Sparkle.swift"; sourceTree = ""; }; D7EF4F031AB5608000D46A0E /* LTMorphingEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTMorphingEffect.swift; sourceTree = ""; }; D7EF4F061AB5612C00D46A0E /* LTCharacterLimbo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTCharacterLimbo.swift; sourceTree = ""; }; D7EF4F091AB561A400D46A0E /* LTEmitterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LTEmitterView.swift; sourceTree = ""; }; /* 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 = ""; }; D72A94DF1F7CAF8B007E5157 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; D73DFD211F5056A700F84122 /* LTMorphingLabelUITests */ = { isa = PBXGroup; children = ( D73DFD221F5056A700F84122 /* LTMorphingLabelUITests.swift */, D73DFD241F5056A700F84122 /* Info.plist */, ); path = LTMorphingLabelUITests; sourceTree = ""; }; 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 = ""; }; D74AD96F195171E7009A2ACD /* Products */ = { isa = PBXGroup; children = ( D74AD96E195171E7009A2ACD /* Morphing.app */, D7D4B01F1A5E87D50087F83D /* MorphingLabel.framework */, D7934DC61A63AF1100AE04CE /* LTMorphingLabelTests.xctest */, D73DFD1A1F4DB5CC00F84122 /* MorphingLabel.framework */, D73DFD201F5056A700F84122 /* LTMorphingLabelUITests.xctest */, ); name = Products; sourceTree = ""; }; 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 = ""; }; D74AD971195171E7009A2ACD /* Supporting Files */ = { isa = PBXGroup; children = ( D74AD972195171E7009A2ACD /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 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 = ""; }; D7868570246848E100D4C46F /* SwiftUI */ = { isa = PBXGroup; children = ( D764373D2467A01A0037C36B /* MorphingText.swift */, ); path = SwiftUI; sourceTree = ""; }; D7934DC71A63AF1100AE04CE /* LTMorphingLabelTests */ = { isa = PBXGroup; children = ( D7934DCA1A63AF1100AE04CE /* LTMorphingLabelTests.swift */, D7934DC81A63AF1100AE04CE /* Supporting Files */, ); path = LTMorphingLabelTests; sourceTree = ""; }; D7934DC81A63AF1100AE04CE /* Supporting Files */ = { isa = PBXGroup; children = ( D7934DC91A63AF1100AE04CE /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D7D4B0201A5E87D50087F83D /* LTMorphingLabel */ = { isa = PBXGroup; children = ( D7D4B0231A5E87D50087F83D /* LTMorphingLabel.h */, D7D4B0211A5E87D50087F83D /* Supporting Files */, ); path = LTMorphingLabel; sourceTree = ""; }; D7D4B0211A5E87D50087F83D /* Supporting Files */ = { isa = PBXGroup; children = ( D7D4B0221A5E87D50087F83D /* Info.plist */, D73DFD1B1F4DB5CC00F84122 /* tvOS-Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* 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 ================================================ ================================================ FILE: LTMorphingLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/LTMorphingLabelDemo.xcscheme ================================================ ================================================ FILE: LTMorphingLabelDemo.xcodeproj/xcshareddata/xcschemes/MorphingLabel.xcscheme ================================================ ================================================ FILE: LTMorphingLabelTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ 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 ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ 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 ![Language](https://img.shields.io/badge/language-Swift%205-orange.svg) [![CocoaPods](https://img.shields.io/cocoapods/v/LTMorphingLabel.svg?style=flat)](https://github.com/lexrus/LTMorphingLabel) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Accio supported](https://img.shields.io/badge/Accio-supported-0A7CF5.svg?style=flat)](https://github.com/JamitLabs/Accio) ![License](https://img.shields.io/github/license/lexrus/LTMorphingLabel.svg?style=flat) 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_) LTMorphingLabel #### [.evaporate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BEvaporate.swift) LTMorphingLabel-Evaporate #### [.fall](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BFall.swift) LTMorphingLabel-Fall #### [.pixelate](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BPixelate.swift) LTMorphingLabel-Pixelate #### [.sparkle](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BSparkle.swift) 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) LTMorphingLabel-Burn #### [.anvil](https://github.com/lexrus/LTMorphingLabel/blob/master/LTMorphingLabel/LTMorphingLabel%2BAnvil.swift) 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" ``` ![UIKitExample1](https://github.com/jonathanwuki/LTMorphingLabel/assets/11484046/bba7138e-1ef8-4714-8792-f34349434761) 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 ``` ![UIKitExample2](https://github.com/jonathanwuki/LTMorphingLabel/assets/11484046/13ab83a6-7f1f-4aac-b0eb-d6172773a671) ### 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) } } ``` ![LTMorphingLabelSwiftUI](https://user-images.githubusercontent.com/219689/81505494-2c528c80-9322-11ea-9bdb-b208dd38a5e6.png) ## 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 ./