简体   繁体   中英

Custom CALayer Animation

I have a UIView with a layer that is doing all the drawing for me. So now when I change a value of my view it forwards that to the layer. And when I am in a UIView-Animaiton Block I'd like that change to be animated.

So what I currently do:

class SampleView: UIView {
    var myProperty: CGFloat {
        set {
            sampleLayer.myProperty = newValue
        }
        get {
            return sampleLayer.myProperty
        }
    }

    override class var layerClass: AnyClass {
        return SampleViewLayer.self
    }

    private var sampleLayer: SampleViewLayer {
        return layer as! SampleViewLayer
    }
}

class SampleViewLayer: CALayer {
    @NSManaged public var myProperty: CGFloat

    override func draw(in ctx: CGContext) {
        // Incredible beautiful drawing is happening here depending on myProperty
    }

    override static func needsDisplay(forKey key: String) -> Bool {
        if key == "myProperty" {
            return true
        }
        return super.needsDisplay(forKey: key)
    }

    override func action(forKey event: String) -> CAAction? {

        if event == "myProperty" {

            // 1. How do I find out if the change should be animated?

            let animation = CABasicAnimation(keyPath: event)
            animation.fromValue = presentation()?.value(forKey: event)

            // 2. How do I find out the proper timingFunction as well as the proper duration?
            animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
            animation.duration = 1.0

            return animation
        }

        return super.action(forKey: event)
    }
}

And I want to be able to animate it like this:

....
instanceOfMySampleView.myProperty = 0 // inital value should be set without animation
UIView.animate(withDuration: 4, animations: {
    self.instanceOfMySampleView.myProperty = 10  // should animate to this value
})
....

So the two actual questions are inside my sample code... 1. How do I find out if the change should be animated? So how to figure out it happened inside a UIView-Animation-Block?

  1. If it's animated, how to find the proper params for duration and timingFunction?

Also. If I create an instance of my View in code set it's myProperty value to the initial value and then directly do a UIViewAnimationBlock, the PresentationLayer will be nil and so my animation will not work properly...

Unless some changes have been made since I last looked into it I would say you can not get those values. And it is a pity no API is provided for it.

If your calls to animate views are manual (you are calling these animations) then I suggest you to replace all of these calls with some custom ones. Like AnimationManager.animate(withDuration:... this method then calls the UIView corresponding methods so you need to replace all your calls with these. Once that is done you should see the same result as you currently do.

Now you need to add logic into this code to save the values of the curves, durations... A basic implementation is to save the new values when the animation block starts and then remove them once it ends (not on completion but the last line in the animation block).

A bit more complex system is to create a stack (array should do) of settings rather then a single value. On start you add an object and on end you simply remove it. The reason for this is the animation calls may be nested and simply removing the animation settings may not be enough. The second reason is you may need to also add functionality performWithoutAnimations which is also on UIView , in this case you just append a null object to the stack.

In any of the 2 cases you may then get AnimationManager.isAnimating , AnimationManager.animationDuration , AnimationManager.animationCurve ... So this works nicely from your own calls to the animation. But to make this general (for instance on device orientation change) seems to be quite an issue. I am pretty sure these data must be somewhere and would be glad to access them.

I hope this system helps you unless you find a more proper solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM