Skip to content

Instantly share code, notes, and snippets.

class LKBoundsDidChangeAnimation : CABasicAnimation {
@objc var bounds : CGRect = CGRect.zero
override func copy(with zone: NSZone? = nil) -> Any {
let result = super.copy(with: zone)
if let action = result as? Self {
action.bounds = bounds
return action
}
return result
extension LKLabel {
open override func action(for layer: CALayer, forKey event: String) -> CAAction? {
let result = super.action(for: layer, forKey: event)
if event == keyPath(\CALayer.bounds) && result != nil && UIView.inheritedAnimationDuration > 0 {
let textDrawingBoundsAction = LKBoundsDidChangeAction(fromBounds: layer.bounds)
let action = LKCompositeAction(actions:[result!, textDrawingBoundsAction])
return action
}
return result
}
open class LKLabel : UILabel {
open override class var layerClass: AnyClass {
get {
return LKLabelLayer.self
}
}
/// The underlying attributed string drawn by the label, if set, the label ignores the `font`,
/// `textColor`, `shadowColor`, and `shadowOffset` properties.
/// If `.paragraphStyle` attribute is absent in the attributed string, it is created incorporating
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,
var interpolatedFromAttributedText : NSAttributedString? {
get {
return fill(withInterpolatedAttributes: fromAttributedText)
}
}
var interpolatedToAttributedText : NSAttributedString? {
get {
if toAttributedText != nil {
return fill(withInterpolatedAttributes: 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 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
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,
protocol LKNSDictionaryCoding {
static func lk_dictEncode(object: AnyObject?)->NSMutableDictionary
static func lk_dictDecode(dictionaryRepresentation dictionary: NSDictionary?)->Self
}
let foregroundColorKey = NSAttributedString.Key.foregroundColor.rawValue
let rangeString = NSStringFromRange(NSRange(location:0, length: attributedText.length))
let keyPath = "\(foregroundColorKey).\(rangeString).r"