Conceptually understanding Core Animation

  • I'm sorry for asking these basic questions, but I have a hard time
    understanding some of the CoreAnimation concepts fully. This is a
    follow-up on (http://www.cocoabuilder.com/archive/message/cocoa/2008/1/14/196457
    ).

    Even after having read the CA Guide, I don't understand what "state" a
    layer is left in after having animated it:

    I have a root layer in my layer-hosting view. The root layer has
    several sublayers being added and removed over time. I have chosen to
    subclass CALayer for my sublayer instances in order to obtain a nice
    encapsulation. I now simply call [myLayer appearAtPosition:pos] and
    several other similar (and more complicated) methods. I also have a
    few instance variables in my subclass although that can be achieved
    without subclassing.

    When I'm animating a sublayer, explicitly in my case, I'd expect the
    layer's property after the animation to be that of the toValue. But it
    isn't - even if I set the fillMode like below:

    // Code from myLayer.m
    CABasicAnimation *anim  = [CABasicAnimation
    animationWithKeyPath:@"position"];
    anim.toValue            = [NSValue valueWithPoint:endPos];
    anim.timingFunction      = [CAMediaTimingFunction
    functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.duration            = MyAnimationDurationFromPointToPoint
    (startPos, endPos);
    anim.fillMode            = kCAFillModeForwards;
    anim.removedOnCompletion = NO;
    anim.delegate            = self;
    [self addAnimation:anim forKey:@"position"];

    Even though the layer appears at endPos after the animation, the
    layer's position property is still startPos. That doesn't make sense
    to me. At all.

    And if I then call [self.superlayer setNeedsDisplay] in the -
    animationDidStop:finished: delegate method, the just animated layer
    simply disappears). If I set the layer's position to endPos after
    animation, the layer jumps to startPos and animates from startPos to
    endPos using the default animation values (implicit animation, I guess).

    - How do I get the layer to stay at the endPos after an explicit
    animation?
    - Am I "wrong" in using layers instead of views as my main visual
    element class?
      The user must be able to click on them and drag them around. Think
    of a card game type of application.

    If I don't set removedOnCompletion to NO, the layer goes back to
    startPos after animation although, conceptually, we're just talking
    about removing the animation - after it's done. This is where I don't
    understand the concept, because I'd think that the animation is just
    the WAY the layer goes from start to end. Once the layer has been
    animated, and it's at its end position, the animation's role is over.
    I think the documentation could do a better job of explaining these
    issues.

    Another thing that puzzles me with regards to the animation object is
    that it doesn't go away from the layer even if I call [self
    removeAllAnimations] in my animationDidStop:finished: delegate method.
    Calling [self animationForKey:@"position"] after -removeAllAnimations
    (or -animationForKey:@"position"), it still returns the animation
    object.

    I'm thinking of layers as lightweight views, in broad terms, but I
    must be making some wrong assumptions in doing so.

    Any enlightening will be highly appreciated.

    Cheers,
    Joachim
  • On Jan 18, 2008, at 6:01 AM, Joachim wrote:

    > I'm sorry for asking these basic questions, but I have a hard time
    > understanding some of the CoreAnimation concepts fully. This is a
    > follow-up on (http://www.cocoabuilder.com/archive/message/cocoa/2008/1/14/196457
    > ).
    >
    > Even after having read the CA Guide, I don't understand what "state"
    > a layer is left in after having animated it:

    Keep in mind that the Core Animation architecture has 3 components:
    layer tree, presentation tree and the render tree (discussed in Core
    Animation Architecture).

    The layer tree holds the model values (that is the real values of the
    various animatable properties)
    The presentation tree holds the currently displayed values (the values
    as an animation is in flight)
    The render tree is responsible for actually compositing it all.

    If you use an implied animation (change the value in the layer) the
    animation occurs over time.  I think this is probably clear to everyone.
    If you use an explicit animation (from the first chapter)

    <excerpt>

    Animatable properties can also be explicitly animated. To explicitly
    animate a property you create an instance of one of Core Animation’s
    animation classes and specify the required visual effects. An explicit
    animation doesn’t change the value of the property in the layer, it
    simply animates it in the display.

    </excerpt>

    <comment>

    I see where this should be repeated in the Animation chapter and the
    Architecture chapter. I've made a note of this.

    </comment>

    so they only have an effect on the presentation layer.

    So, you do your explicit animation...

    > When I'm animating a sublayer, explicitly in my case, I'd expect the
    > layer's property after the animation to be that of the toValue. But
    > it isn't - even if I set the fillMode like below:
    >
    > // Code from myLayer.m
    > CABasicAnimation *anim  = [CABasicAnimation
    > animationWithKeyPath:@"position"];
    > anim.toValue            = [NSValue valueWithPoint:endPos];
    > anim.timingFunction      = [CAMediaTimingFunction
    > functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    > anim.duration            = MyAnimationDurationFromPointToPoint
    > (startPos, endPos);
    > anim.fillMode            = kCAFillModeForwards;
    > anim.removedOnCompletion = NO;
    > anim.delegate            = self;
    > [self addAnimation:anim forKey:@"position"];
    >

    The reason you're not seeing the position value be the end value is
    that it isn't supposed to be. You're only changing the presentation
    layer using explicit animations. when you ask for the position value
    you're asking for the layer-tree value.

    > Even though the layer appears at endPos after the animation, the
    > layer's position property is still startPos. That doesn't make sense
    > to me. At all.
    >

    layer tree, presentation tree

    > And if I then call [self.superlayer setNeedsDisplay] in the -
    > animationDidStop:finished: delegate method, the just animated layer
    > simply disappears). If I set the layer's position to endPos after
    > animation, the layer jumps to startPos and animates from startPos to
    > endPos using the default animation values (implicit animation, I
    > guess).

    Yes.  if you turn off animation temporarily using a transaction in the
    animationDidStop:finished: implementation, then change position, you'd
    be find. Turning off animations is discussed in the Transactions
    chapter.

    >
    >
    > - How do I get the layer to stay at the endPos after an explicit
    > animation?

    That's above.

    >
    > - Am I "wrong" in using layers instead of views as my main visual
    > element class?

    not necessarily.

    >
    > The user must be able to click on them and drag them around. Think
    > of a card game type of application.

    Have a look at GeekGameBoard to see how they do this exact thing.

    >
    >
    > If I don't set removedOnCompletion to NO, the layer goes back to
    > startPos after animation although, conceptually, we're just talking
    > about removing the animation - after it's done. This is where I
    > don't understand the concept, because I'd think that the animation
    > is just the WAY the layer goes from start to end. Once the layer has
    > been animated, and it's at its end position, the animation's role is
    > over. I think the documentation could do a better job of explaining
    > these issues.
    >

    It appears it could. (I've made notes)

    remember that animations are essentially 'actions' (Actions chapter).

    removedOnCompletion basically means "is the animation removed from the
    layer's animations when it is done". this is a convenience basically,
    it means that if you intend to use the animation once, you don't need
    to implement the delegate method to remove from the animation from the
    layer explicitly upon completion.

    The fillMode controls what happens visually when the animation is
    completed.  If it is set to none, then it is removed and the layer
    value is used instead. if it is set to one of the other modes it will
    still be displayed (in the state specified by that fillMode), but only
    as long as the animation is still 'attached' to the layer.

    > Another thing that puzzles me with regards to the animation object
    > is that it doesn't go away from the layer even if I call [self
    > removeAllAnimations] in my animationDidStop:finished: delegate
    > method. Calling [self animationForKey:@"position"] after -
    > removeAllAnimations (or -animationForKey:@"position"), it still
    > returns the animation object.

    all removeAllAnimations does is clear out the animations that are
    attached to the layer in the actions dictionary. it doesn't change the
    fact that the layer actually has default animations for "position"
    that are acquired elsewhere. the animations you attach to a layer
    (stored in the actions dictionary) are simply the first place
    animations are looked for. after that the delegate gets a shot if it
    implements the correct method, and then the layer itself gets a shot.
    it is the layer class that provides the default animation that you're
    getting back.

    <comment>
    This could definitely be clearer. I've made a note.
    </comment>

    >
    >
    > I'm thinking of layers as lightweight views, in broad terms, but I
    > must be making some wrong assumptions in doing so.
    >

    Nope.. that's right.
  • Hi Scott,

    I'm not seeing the behavior described here (at least my understanding
    of what is described here is not happening :)

    I have two animations, one explicit and one implied. When the implied
    animation is run (i.e. I set the layers position) the following code
    does what I expect (the presentation layer's position changes as I
    click).

    - (void)mouseDown:(NSEvent *)event {
      NSPoint point = [self convertPoint:[event locationInWindow]
    fromView:nil];
      CALayer *presLayer = [self.photoLayer presentationLayer];
      CALayer *layer = [presLayer hitTest:*(CGPoint*)&point];
      NSLog(@"pres pos.x = %f, pres pos.y = %f",
    presLayer.frame.origin.x, presLayer.frame.origin.y);
      ...
    }

    When I'm running the explicit animation the presentation layer's
    position does not change.

    Is it just the render tree that updates when an explicit animation is
    used?

    If this is a bug I'd be glad to submit the sample code to reproduce.

    Thanks,

    -bd-
    http://bill.dudney.net/roller/objc

    On Jan 18, 2008, at 5:37 AM, Scott Anguish wrote:

    >
    > On Jan 18, 2008, at 6:01 AM, Joachim wrote:
    >
    >> I'm sorry for asking these basic questions, but I have a hard time
    >> understanding some of the CoreAnimation concepts fully. This is a
    >> follow-up on (http://www.cocoabuilder.com/archive/message/cocoa/2008/1/14/196457
    >> ).
    >>
    >> Even after having read the CA Guide, I don't understand what
    >> "state" a layer is left in after having animated it:
    >
    >
    > Keep in mind that the Core Animation architecture has 3 components:
    > layer tree, presentation tree and the render tree (discussed in Core
    > Animation Architecture).
    >
    > The layer tree holds the model values (that is the real values of
    > the various animatable properties)
    > The presentation tree holds the currently displayed values (the
    > values as an animation is in flight)
    > The render tree is responsible for actually compositing it all.
    >
    > If you use an implied animation (change the value in the layer) the
    > animation occurs over time.  I think this is probably clear to
    > everyone.
    > If you use an explicit animation (from the first chapter)
    >
    > <excerpt>
    >
    > Animatable properties can also be explicitly animated. To explicitly
    > animate a property you create an instance of one of Core Animation’s
    > animation classes and specify the required visual effects. An
    > explicit animation doesn’t change the value of the property in the
    > layer, it simply animates it in the display.
    >
    > </excerpt>
    >
    > <comment>
    >
    > I see where this should be repeated in the Animation chapter and the
    > Architecture chapter. I've made a note of this.
    >
    > </comment>
    >
    > so they only have an effect on the presentation layer.
    >
    > So, you do your explicit animation...
    >
    >> When I'm animating a sublayer, explicitly in my case, I'd expect
    >> the layer's property after the animation to be that of the toValue.
    >> But it isn't - even if I set the fillMode like below:
    >>
    >> // Code from myLayer.m
    >> CABasicAnimation *anim  = [CABasicAnimation
    >> animationWithKeyPath:@"position"];
    >> anim.toValue            = [NSValue valueWithPoint:endPos];
    >> anim.timingFunction      = [CAMediaTimingFunction
    >> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    >> anim.duration            = MyAnimationDurationFromPointToPoint
    >> (startPos, endPos);
    >> anim.fillMode            = kCAFillModeForwards;
    >> anim.removedOnCompletion = NO;
    >> anim.delegate            = self;
    >> [self addAnimation:anim forKey:@"position"];
    >>
    >
    > The reason you're not seeing the position value be the end value is
    > that it isn't supposed to be. You're only changing the presentation
    > layer using explicit animations. when you ask for the position value
    > you're asking for the layer-tree value.
    >
    >
    >
    >> Even though the layer appears at endPos after the animation, the
    >> layer's position property is still startPos. That doesn't make
    >> sense to me. At all.
    >>
    >
    > layer tree, presentation tree
    >
    >> And if I then call [self.superlayer setNeedsDisplay] in the -
    >> animationDidStop:finished: delegate method, the just animated layer
    >> simply disappears). If I set the layer's position to endPos after
    >> animation, the layer jumps to startPos and animates from startPos
    >> to endPos using the default animation values (implicit animation, I
    >> guess).
    >
    > Yes.  if you turn off animation temporarily using a transaction in
    > the animationDidStop:finished: implementation, then change position,
    > you'd be find. Turning off animations is discussed in the
    > Transactions chapter.
    >
    >>
    >>
    >> - How do I get the layer to stay at the endPos after an explicit
    >> animation?
    >
    > That's above.
    >
    >>
    >> - Am I "wrong" in using layers instead of views as my main visual
    >> element class?
    >
    > not necessarily.
    >
    >>
    >> The user must be able to click on them and drag them around. Think
    >> of a card game type of application.
    >
    > Have a look at GeekGameBoard to see how they do this exact thing.
    >
    >>
    >>
    >> If I don't set removedOnCompletion to NO, the layer goes back to
    >> startPos after animation although, conceptually, we're just talking
    >> about removing the animation - after it's done. This is where I
    >> don't understand the concept, because I'd think that the animation
    >> is just the WAY the layer goes from start to end. Once the layer
    >> has been animated, and it's at its end position, the animation's
    >> role is over. I think the documentation could do a better job of
    >> explaining these issues.
    >>
    >
    > It appears it could. (I've made notes)
    >
    > remember that animations are essentially 'actions' (Actions chapter).
    >
    > removedOnCompletion basically means "is the animation removed from
    > the layer's animations when it is done". this is a convenience
    > basically, it means that if you intend to use the animation once,
    > you don't need to implement the delegate method to remove from the
    > animation from the layer explicitly upon completion.
    >
    >
    > The fillMode controls what happens visually when the animation is
    > completed.  If it is set to none, then it is removed and the layer
    > value is used instead. if it is set to one of the other modes it
    > will still be displayed (in the state specified by that fillMode),
    > but only as long as the animation is still 'attached' to the layer.
    >
    >> Another thing that puzzles me with regards to the animation object
    >> is that it doesn't go away from the layer even if I call [self
    >> removeAllAnimations] in my animationDidStop:finished: delegate
    >> method. Calling [self animationForKey:@"position"] after -
    >> removeAllAnimations (or -animationForKey:@"position"), it still
    >> returns the animation object.
    >
    >
    > all removeAllAnimations does is clear out the animations that are
    > attached to the layer in the actions dictionary. it doesn't change
    > the fact that the layer actually has default animations for
    > "position" that are acquired elsewhere. the animations you attach to
    > a layer (stored in the actions dictionary) are simply the first
    > place animations are looked for. after that the delegate gets a shot
    > if it implements the correct method, and then the layer itself gets
    > a shot. it is the layer class that provides the default animation
    > that you're getting back.
    >
    > <comment>
    > This could definitely be clearer. I've made a note.
    > </comment>
    >
    >>
    >>
    >> I'm thinking of layers as lightweight views, in broad terms, but I
    >> must be making some wrong assumptions in doing so.
    >>
    >
    > Nope.. that's right.
  • FWIW: filed under problem id #5723911 with bugreport.apple.com...

    -bd-
    http://bill.dudney.net/roller/objc

    On Feb 4, 2008, at 3:55 PM, Bill Dudney wrote:

    > Hi Scott,
    >
    > I'm not seeing the behavior described here (at least my
    > understanding of what is described here is not happening :)
    >
    > I have two animations, one explicit and one implied. When the
    > implied animation is run (i.e. I set the layers position) the
    > following code does what I expect (the presentation layer's position
    > changes as I click).
    >
    > - (void)mouseDown:(NSEvent *)event {
    > NSPoint point = [self convertPoint:[event locationInWindow]
    > fromView:nil];
    > CALayer *presLayer = [self.photoLayer presentationLayer];
    > CALayer *layer = [presLayer hitTest:*(CGPoint*)&point];
    > NSLog(@"pres pos.x = %f, pres pos.y = %f",
    > presLayer.frame.origin.x, presLayer.frame.origin.y);
    > ...
    > }
    >
    > When I'm running the explicit animation the presentation layer's
    > position does not change.
    >
    > Is it just the render tree that updates when an explicit animation
    > is used?
    >
    > If this is a bug I'd be glad to submit the sample code to reproduce.
    >
    > Thanks,
    >
    > -bd-
    > http://bill.dudney.net/roller/objc
    >
    > On Jan 18, 2008, at 5:37 AM, Scott Anguish wrote:
    >
    >>
    >> On Jan 18, 2008, at 6:01 AM, Joachim wrote:
    >>
    >>> I'm sorry for asking these basic questions, but I have a hard time
    >>> understanding some of the CoreAnimation concepts fully. This is a
    >>> follow-up on (http://www.cocoabuilder.com/archive/message/cocoa/2008/1/14/196457
    >>> ).
    >>>
    >>> Even after having read the CA Guide, I don't understand what
    >>> "state" a layer is left in after having animated it:
    >>
    >>
    >> Keep in mind that the Core Animation architecture has 3 components:
    >> layer tree, presentation tree and the render tree (discussed in
    >> Core Animation Architecture).
    >>
    >> The layer tree holds the model values (that is the real values of
    >> the various animatable properties)
    >> The presentation tree holds the currently displayed values (the
    >> values as an animation is in flight)
    >> The render tree is responsible for actually compositing it all.
    >>
    >> If you use an implied animation (change the value in the layer) the
    >> animation occurs over time.  I think this is probably clear to
    >> everyone.
    >> If you use an explicit animation (from the first chapter)
    >>
    >> <excerpt>
    >>
    >> Animatable properties can also be explicitly animated. To
    >> explicitly animate a property you create an instance of one of Core
    >> Animation’s animation classes and specify the required visual
    >> effects. An explicit animation doesn’t change the value of the
    >> property in the layer, it simply animates it in the display.
    >>
    >> </excerpt>
    >>
    >> <comment>
    >>
    >> I see where this should be repeated in the Animation chapter and
    >> the Architecture chapter. I've made a note of this.
    >>
    >> </comment>
    >>
    >> so they only have an effect on the presentation layer.
    >>
    >> So, you do your explicit animation...
    >>
    >>> When I'm animating a sublayer, explicitly in my case, I'd expect
    >>> the layer's property after the animation to be that of the
    >>> toValue. But it isn't - even if I set the fillMode like below:
    >>>
    >>> // Code from myLayer.m
    >>> CABasicAnimation *anim  = [CABasicAnimation
    >>> animationWithKeyPath:@"position"];
    >>> anim.toValue            = [NSValue valueWithPoint:endPos];
    >>> anim.timingFunction      = [CAMediaTimingFunction
    >>> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    >>> anim.duration            = MyAnimationDurationFromPointToPoint
    >>> (startPos, endPos);
    >>> anim.fillMode            = kCAFillModeForwards;
    >>> anim.removedOnCompletion = NO;
    >>> anim.delegate            = self;
    >>> [self addAnimation:anim forKey:@"position"];
    >>>
    >>
    >> The reason you're not seeing the position value be the end value is
    >> that it isn't supposed to be. You're only changing the presentation
    >> layer using explicit animations. when you ask for the position
    >> value you're asking for the layer-tree value.
    >>
    >>
    >>
    >>> Even though the layer appears at endPos after the animation, the
    >>> layer's position property is still startPos. That doesn't make
    >>> sense to me. At all.
    >>>
    >>
    >> layer tree, presentation tree
    >>
    >>> And if I then call [self.superlayer setNeedsDisplay] in the -
    >>> animationDidStop:finished: delegate method, the just animated
    >>> layer simply disappears). If I set the layer's position to endPos
    >>> after animation, the layer jumps to startPos and animates from
    >>> startPos to endPos using the default animation values (implicit
    >>> animation, I guess).
    >>
    >> Yes.  if you turn off animation temporarily using a transaction in
    >> the animationDidStop:finished: implementation, then change
    >> position, you'd be find. Turning off animations is discussed in the
    >> Transactions chapter.
    >>
    >>>
    >>>
    >>> - How do I get the layer to stay at the endPos after an explicit
    >>> animation?
    >>
    >> That's above.
    >>
    >>>
    >>> - Am I "wrong" in using layers instead of views as my main visual
    >>> element class?
    >>
    >> not necessarily.
    >>
    >>>
    >>> The user must be able to click on them and drag them around. Think
    >>> of a card game type of application.
    >>
    >> Have a look at GeekGameBoard to see how they do this exact thing.
    >>
    >>>
    >>>
    >>> If I don't set removedOnCompletion to NO, the layer goes back to
    >>> startPos after animation although, conceptually, we're just
    >>> talking about removing the animation - after it's done. This is
    >>> where I don't understand the concept, because I'd think that the
    >>> animation is just the WAY the layer goes from start to end. Once
    >>> the layer has been animated, and it's at its end position, the
    >>> animation's role is over. I think the documentation could do a
    >>> better job of explaining these issues.
    >>>
    >>
    >> It appears it could. (I've made notes)
    >>
    >> remember that animations are essentially 'actions' (Actions chapter).
    >>
    >> removedOnCompletion basically means "is the animation removed from
    >> the layer's animations when it is done". this is a convenience
    >> basically, it means that if you intend to use the animation once,
    >> you don't need to implement the delegate method to remove from the
    >> animation from the layer explicitly upon completion.
    >>
    >>
    >> The fillMode controls what happens visually when the animation is
    >> completed.  If it is set to none, then it is removed and the layer
    >> value is used instead. if it is set to one of the other modes it
    >> will still be displayed (in the state specified by that fillMode),
    >> but only as long as the animation is still 'attached' to the layer.
    >>
    >>> Another thing that puzzles me with regards to the animation object
    >>> is that it doesn't go away from the layer even if I call [self
    >>> removeAllAnimations] in my animationDidStop:finished: delegate
    >>> method. Calling [self animationForKey:@"position"] after -
    >>> removeAllAnimations (or -animationForKey:@"position"), it still
    >>> returns the animation object.
    >>
    >>
    >> all removeAllAnimations does is clear out the animations that are
    >> attached to the layer in the actions dictionary. it doesn't change
    >> the fact that the layer actually has default animations for
    >> "position" that are acquired elsewhere. the animations you attach
    >> to a layer (stored in the actions dictionary) are simply the first
    >> place animations are looked for. after that the delegate gets a
    >> shot if it implements the correct method, and then the layer itself
    >> gets a shot. it is the layer class that provides the default
    >> animation that you're getting back.
    >>
    >> <comment>
    >> This could definitely be clearer. I've made a note.
    >> </comment>
    >>
    >>>
    >>>
    >>> I'm thinking of layers as lightweight views, in broad terms, but I
    >>> must be making some wrong assumptions in doing so.
    >>>
    >>
    >> Nope.. that's right.

previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today