user2023106
user2023106

Reputation:

Animate sublayers of a layer

I'm having a view that draws 2 layers;

Now when I switch my path I want to animate both layers at the same time. So to do that I first had 2 separate layers and added an animation to each one of them. That worked, but I didn't like the fact that I had to write the animation for each one of them.

That's why I decided to create a CAShapeLayer subclass and move the gradient into the line layer so in terms of hierarchy it looks like this;

In code;

class LineLayer: CAShapeLayer {
    // Configuration
    private var configuration: ChartConfiguration!

    // Layers
    private var backgroundLayer: CAGradientLayer!

    init(configuration: ChartConfiguration) {
        super.init()
        self.configuration = configuration
        configureLayers()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func configureLayers() {
        addLineLayer()
        addBackgroundLayer()
    }

    private func addLineLayer() {
        self.fillColor = UIColor.clear.cgColor
        self.strokeColor = configuration.lineColor
        self.lineWidth = configuration.lineWidth
    }

    private func addBackgroundLayer() {
        backgroundLayer = CAGradientLayer()
        backgroundLayer.anchorPoint = CGPoint(x: 0, y: 0)
        backgroundLayer.colors = [UIColor.systemGreen.withAlphaComponent(0.24).cgColor, UIColor.systemGreen.withAlphaComponent(0).cgColor]
        backgroundLayer.startPoint = CGPoint(x: 0, y: 0)
        backgroundLayer.endPoint = CGPoint(x: 0, y: 1)
        self.addSublayer(backgroundLayer)
    }

    public func updateBackgroundLayer(frame: CGRect, mask: CAShapeLayer) {
        backgroundLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
        backgroundLayer.mask = mask
    }
}

Then I animated the parent (line) and thought the children (gradient) would move along. Unfortunately this doesn't happen. My animation code looks like this;

    lineLayer = LineLayer(configuration: configuration)
    lineLayer.path = linePath
    self.layer.addSublayer(lineLayer)

    private func addPathAnimation() {
        let animation = CABasicAnimation(keyPath: "path")
        animation.duration = configuration.animationDuration
        animation.fromValue = layer.path != nil ? layer.path : linePath
        animation.toValue = path
        animation.timingFunction = configuration.animationCurve
        layer.add(animation, forKey: nil)
        layer.path = path
    }

Is it possible to animate the children when only animating the parent? Or do I just have to stick with separate layers added to the view and animate each one of them?

Upvotes: 2

Views: 1101

Answers (1)

matt
matt

Reputation: 535139

Is it possible to animate the children when only animating the parent?

Yes (if I'm understanding the question correctly). You add to the parent a CAAnimationGroup. That group coordinates multiple child CAAnimations. Assuming these are some kind of property animation, the keyPath for each child animation can be a property of the parent or a property of any of its child sublayers (using the notation "sublayers.name.property", where name is the value of the child's name property).

Upvotes: 1

Related Questions