Skip to content

Commit

Permalink
introduce LinearGradient animation
Browse files Browse the repository at this point in the history
  • Loading branch information
iBlacksus committed Aug 30, 2020
1 parent bdc3b49 commit f8fc7d3
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import AppKit

class AnimationUtils {

class func layerForNodeRenderer(_ renderer: NodeRenderer, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
class func layerForNodeRenderer(_ renderer: NodeRenderer, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true, isGradient: Bool = false) -> LayerProtocol {

let node = renderer.node
if let cachedLayer = renderer.layer {
Expand All @@ -18,10 +18,10 @@ class AnimationUtils {
}

// 'sublayer' is for actual CAAnimations, and 'layer' is for manual transforming and hierarchy changes
let sublayer = ShapeLayer()
let sublayer: LayerProtocol = isGradient ? GradientLayer () : ShapeLayer()
sublayer.shouldRenderContent = shouldRenderContent

let layer = ShapeLayer()
let layer: LayerProtocol = isGradient ? GradientLayer () : ShapeLayer()
layer.addSublayer(sublayer)
layer.masksToBounds = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,15 @@ func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationConte

completion()
}

layer.path = fromLocus.toCGPath()
layer.setupStrokeAndFill(shape)

if let layer = layer as? ShapeLayer {
layer.path = fromLocus.toCGPath()
layer.setupStrokeAndFill(shape)
} else if let layer = layer as? GradientLayer {
let maskLayer = CAShapeLayer()
maskLayer.path = fromLocus.toCGPath()
layer.mask = maskLayer
}

let animationId = animation.ID
layer.add(generatedAnimation, forKey: animationId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func addPathAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
return
}

let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false)
let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false, isGradient: shape.fill is LinearGradient)

// Creating proper animation
let generatedAnim = generatePathAnimation(
Expand Down Expand Up @@ -52,9 +52,11 @@ func addPathAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
completion()
}

//layer.path = RenderUtils.toCGPath(shape.form).copy(using: &layer.transform)
layer.path = shape.form.toCGPath()
layer.setupStrokeAndFill(shape)
if let layer = layer as? ShapeLayer {
//layer.path = RenderUtils.toCGPath(shape.form).copy(using: &layer.transform)
layer.path = shape.form.toCGPath()
layer.setupStrokeAndFill(shape)
}

layer.add(generatedAnim, forKey: animation.ID)
animation.removeFunc = { [weak layer] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
let toShape = shapeAnimation.getVFunc()(animation.autoreverses ? 0.5 : 1.0)
let duration = animation.autoreverses ? animation.getDuration() / 2.0 : animation.getDuration()

let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false)
let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false, isGradient: shape.fill is LinearGradient)

// Creating proper animation
let generatedAnimation = generateShapeAnimation(context,
Expand Down Expand Up @@ -89,8 +89,22 @@ func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
completion()
}

layer.path = fromShape.form.toCGPath()
layer.setupStrokeAndFill(fromShape)
if let layer = layer as? ShapeLayer {
layer.path = fromShape.form.toCGPath()
layer.setupStrokeAndFill(fromShape)
} else if let layer = layer as? GradientLayer {
let maskLayer = CAShapeLayer()
maskLayer.path = fromShape.form.toCGPath()
layer.mask = maskLayer

if let color = shape.fill as? LinearGradient {
let properties = color.toCG()
layer.colors = properties.colors
layer.locations = properties.locations
layer.startPoint = CGPoint(x: color.x1, y: color.y1)
layer.endPoint = CGPoint(x: color.x2, y: color.y2)
}
}

let animationId = animation.ID
layer.add(generatedAnimation, forKey: animationId)
Expand Down Expand Up @@ -127,16 +141,25 @@ fileprivate func generateShapeAnimation(_ context: AnimationContext, from: Shape
group.animations?.append(transformAnimation)

// Fill
let fromFillColor = from.fill as? Color ?? Color.clear
let toFillColor = to.fill as? Color ?? Color.clear

if fromFillColor != toFillColor {
let fillAnimation = CABasicAnimation(keyPath: "fillColor")
fillAnimation.fromValue = fromFillColor.toCG()
fillAnimation.toValue = toFillColor.toCG()
fillAnimation.duration = duration

group.animations?.append(fillAnimation)

if from.fill != to.fill {
if let fromFillColor = from.fill as? Color, let toFillColor = to.fill as? Color {
let fillAnimation = CABasicAnimation(keyPath: "fillColor")
fillAnimation.fromValue = fromFillColor.toCG()
fillAnimation.toValue = toFillColor.toCG()
fillAnimation.duration = duration

group.animations?.append(fillAnimation)
} else if let fromFillColor = from.fill as? LinearGradient, let toFillColor = to.fill as? LinearGradient {
let fillAnimation = CABasicAnimation(keyPath: "colors")
let fromProperties = fromFillColor.toCG()
let toProperties = toFillColor.toCG()
fillAnimation.fromValue = fromProperties.colors
fillAnimation.toValue = toProperties.colors
fillAnimation.duration = duration

group.animations?.append(fillAnimation)
}
}

// Stroke
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont
let transactionsDisabled = CATransaction.disableActions()
CATransaction.setDisableActions(true)

let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: true)
let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: true, isGradient: (node as? Shape)?.fill is LinearGradient)

// Creating proper animation
let generatedAnimation = transformAnimationByFunc(transformAnimation,
Expand Down
13 changes: 13 additions & 0 deletions Source/model/draw/Gradient.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import UIKit

open class Gradient: Fill {

public let userSpace: Bool
Expand All @@ -19,4 +21,15 @@ open class Gradient: Fill {

return stops.elementsEqual(other.stops)
}

public func toCG() -> (colors: Array<CGColor>, locations: Array<NSNumber>) {
var colors: Array<CGColor> = []
var locations: Array<NSNumber> = []
for stop in stops {
colors += [stop.color.toCG()]
locations += [NSNumber(value: stop.offset)]
}

return (colors, locations)
}
}
6 changes: 3 additions & 3 deletions Source/render/NodeRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ enum ColoringMode {
}

class CachedLayer {
let rootLayer: ShapeLayer
let animationLayer: ShapeLayer
let rootLayer: LayerProtocol
let animationLayer: LayerProtocol

required init(rootLayer: ShapeLayer, animationLayer: ShapeLayer) {
required init(rootLayer: LayerProtocol, animationLayer: LayerProtocol) {
self.rootLayer = rootLayer
self.animationLayer = animationLayer
}
Expand Down
28 changes: 25 additions & 3 deletions Source/views/ShapeLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,32 @@ import UIKit
import AppKit
#endif

class ShapeLayer: CAShapeLayer {
protocol LayerProtocol: CALayer {
var renderer: NodeRenderer? { get set }
var shouldRenderContent: Bool { get set }
var isForceRenderingEnabled: Bool { get set }
func draw(in ctx: CGContext)
}

class ShapeLayer: CAShapeLayer, LayerProtocol {
weak var renderer: NodeRenderer?
var shouldRenderContent: Bool = true
var isForceRenderingEnabled: Bool = true

override func draw(in ctx: CGContext) {
if !shouldRenderContent {
super.draw(in: ctx)
return
}

renderer?.directRender(in: ctx, force: isForceRenderingEnabled)
}
}

class GradientLayer: CAGradientLayer, LayerProtocol {
weak var renderer: NodeRenderer?
var shouldRenderContent = true
var isForceRenderingEnabled = true
var shouldRenderContent: Bool = true
var isForceRenderingEnabled: Bool = true

override func draw(in ctx: CGContext) {
if !shouldRenderContent {
Expand Down

0 comments on commit f8fc7d3

Please sign in to comment.