I have an NSView
subclass with a property declared like this in the header:
@property (nonatomic) BaseRange range;
BaseRange
is defined as:
typedef struct BaseRange {
float start;
float len;
} BaseRange;
I want to animate the range
property using the NSAnimatablePropertyContainer
protocol.
My class overrides + defaultAnimationForKey:
as required.
The problem is that when I call [myView.animator setRange:<some value>]
(myView
being a instance of the class in question), myView
is sent -setNilValueForKey:
for the range
key at every step of the animation, except for the final value. IOW, the animation doesn't work.
If I define the range
property like so:
@property (nonatomic) NSSize range;
and don't change anything else, no -setNilValueForKey:
message is sent, but rather intermediate values for the range
key, as normal.
But I don't want to use NSSize
, because the range
key should represent a range rather than a a size.
Any suggestions?
Provided you return
CAPropertyAnimation
or its subclass from the+[NSAnimatablePropertyContainer defaultAnimationForKey:]
method, the behaviour is expect, as it works with strict set of values:To my knowledge
CAAnimation
and its subclasses cannot work with arbitrary values beyond this set and focused primarily to work with Core Graphics properties (layers, frames, colors, etc..). On macOS, however, you can useNSAnimation
class instead, which is much more flexible but requires additional customisation to your class. First you should subclassNSAnimation
itself and override the-[NSAnimation setCurrentProgress:]
method (this is not mandatory, but otherwise you won't be able to get smooth enough transition between animation steps):In this implementation:
TDWRange
refers to the custom structure which represents the range;_rangeOwner
refers to the object which has a property of typeTDWRange
;_rangeKeyPath
refers to the key path by which theNSAnimation
subclass can find the property;_targetRange
is the value towards which the animation interpolates;_originalRange
is the value of the property before animation gets started.Then, in your custom view class you should provide a separate means to update a property with the given animation. Provided the animation class is called
TDWRangeAnimation
and the range property is reachable through@"range"
key path, such a method may look like this:You are not required to retain the animation object, since it's maintained by the run loop until the animation finishes.
P.S. Feel free to refer to the gist in case you need a complete implementation sample.