Skip to content

Instantly share code, notes, and snippets.

@edudnyk
edudnyk / LKLabelLayer.swift
Created July 28, 2019 17:01
Initial label layer implementation
import QuartzCore
import UIKit
open class LKLabelLayer : CALayer {
fileprivate var stringDrawingContext : NSStringDrawingContext!
fileprivate var stringDrawingOptions : NSStringDrawingOptions!
@objc open var attributedText : NSAttributedString?
public override init() {
@objc @NSManaged open dynamic var attributedText : NSAttributedString?
open override func action(forKey event: String) -> CAAction? {
if event == keyPath(\LKLabelLayer.attributedText) {
/// Create and return our text interpolating `CAAction` instance here
}
return super.action(forKey:event)
}
open override class func needsDisplay(forKey key: String) -> Bool {
class LKTextDidChangeAction : CAAnimationGroup {
/// Here interpolation context gets stored
@objc var interpolatedAttributeStates : NSMutableDictionary!
var fromAttributedText : NSAttributedString?
var toAttributedText : NSAttributedString?
required override init() {
super.init()
}
let foregroundColorKey = NSAttributedString.Key.foregroundColor.rawValue
let rangeString = NSStringFromRange(NSRange(location:0, length: attributedText.length))
let keyPath = "\(foregroundColorKey).\(rangeString).r"
protocol LKNSDictionaryCoding {
static func lk_dictEncode(object: AnyObject?)->NSMutableDictionary
static func lk_dictDecode(dictionaryRepresentation dictionary: NSDictionary?)->Self
}
extension UIColor : LKNSDictionaryCoding {
static func lk_dictEncode(object: AnyObject?)->NSMutableDictionary {
let color = object as? UIColor
var red: CGFloat = 0,
green: CGFloat = 0,
blue: CGFloat = 0,
alpha: CGFloat = 0
if color?.getRed(&red,
green: &green,
var animations = [CABasicAnimation]()
let rootAttributesKey = keyPath(\LKLabelLayer.currentTextDidChangeAnimation?
.interpolatedAttributeStates)
type(of: self).attributedStringKeys.forEach { (attributeRawValue) in
var shorterTextValue : AnyObject? = nil
let attributedStringKey = NSAttributedString.Key(rawValue: attributeRawValue)
let swapped = self.toAttributedText?.length ?? 0 > self.fromAttributedText?.length ?? 0
let longerText = swapped ? self.toAttributedText : self.fromAttributedText
let shorterText = swapped ? self.fromAttributedText : self.toAttributedText
private static func animationsForAttributeDiff(forRootKey rootKey: String,
attributedStringKey: NSAttributedString.Key,
fromValue: Any?,
toValue: Any?,
in diffRange: NSRange,
attributeStates : NSMutableDictionary,
duration: TimeInterval)->[CABasicAnimation] {
var animations = [CABasicAnimation]()
let appendAnimation : (_ keyPath: String, _ from: Any?, _ to: Any?)->() =
{ (keyPath, from, to) in
var interpolatedFromAttributedText : NSAttributedString? {
get {
return fill(withInterpolatedAttributes: fromAttributedText)
}
}
var interpolatedToAttributedText : NSAttributedString? {
get {
if toAttributedText != nil {
return fill(withInterpolatedAttributes: toAttributedText!)
}
private static func animationsForAlphaSwap(forKeyPath keyPath: String,
fromValue: Any?,
toValue: Any?)->[CABasicAnimation] {
let duration = CATransaction.animationDuration()
guard duration > 0 else { return [CABasicAnimation]() }
let alphaSwapDuration = min(LabelLayerFromToAlphaSwapAnimationDuration, 0.5 * duration)
let alphaPersistDuration = (duration - alphaSwapDuration) / 2.0
let persistFromAlphaAnimation = CABasicAnimation(forKeyPath: keyPath,
fromValue: fromValue,
toValue: fromValue,