mirror of
https://github.com/exyte/Macaw.git
synced 2024-10-26 13:01:25 +03:00
introduce LinearGradient animation
This commit is contained in:
parent
bdc3b499c1
commit
f8fc7d3168
@ -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 {
|
||||
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
@ -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
|
||||
|
@ -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,
|
||||
@ -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)
|
||||
@ -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 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
|
||||
|
||||
if fromFillColor != toFillColor {
|
||||
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)
|
||||
group.animations?.append(fillAnimation)
|
||||
}
|
||||
}
|
||||
|
||||
// Stroke
|
||||
|
@ -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,
|
||||
|
@ -1,3 +1,5 @@
|
||||
import UIKit
|
||||
|
||||
open class Gradient: Fill {
|
||||
|
||||
public let userSpace: Bool
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 = true
|
||||
var isForceRenderingEnabled = true
|
||||
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: Bool = true
|
||||
var isForceRenderingEnabled: Bool = true
|
||||
|
||||
override func draw(in ctx: CGContext) {
|
||||
if !shouldRenderContent {
|
||||
|
Loading…
Reference in New Issue
Block a user