Non Linear CAAnimation of properties

  • Hi List,

    I'm trying to animate X and Z on a curve (rotating image a bit like
    front row does). I can get the position correctly and have it linearly
    animated from one position to the other, but i'd rather have it curve
    a bit before since it would feel more natural than a straight line.

    I thought the easiest way would be to use CAKeyframeAnimation and give
    it a CGPath to follow. But it feels like that only works for animating
    the position attribute or at least only for CGPoint attributes. Is
    that the case ?

    So I tried creating my own CGPoint and have it set the position and
    zPosition. But my new attribute does not get animated. Not even the
    default basic animation. What needs to be done for a property of a
    subclass of CALayer to be animatable ?

    Thanks.
    Bertrand.
  • Hi Bertrand,

    If I understand correctly you want a CAAnimationGroup to get your
    position and zPosition properties to animate at the same time (I've
    only done this on a layer backed view myself but it should work).

    Here is the basic code that I'm using;

    - (CAAnimation *)frameAnimation:(NSRect)aniFrame {
        CAKeyframeAnimation *frameAnimation = [CAKeyframeAnimation
    animationWithKeyPath:@"frame"];
        NSRect start = aniFrame;
        NSRect end = NSInsetRect(aniFrame, -NSWidth(start) * 0.50, -
    NSHeight(start) * 0.50);
        frameAnimation.values = [NSArray arrayWithObjects:
                                  [NSValue valueWithRect:start],
                                  [NSValue valueWithRect:end], nil];
        return frameAnimation;
    }

    - (CABasicAnimation *)rotationAnimation {
        CABasicAnimation *rotation = [CABasicAnimation
    animationWithKeyPath:@"frameRotation"];
        rotation.fromValue = [NSNumber numberWithFloat:0.0f];
        rotation.toValue = [NSNumber numberWithFloat:45.0f];
        return rotation;
    }

    - (CAAnimationGroup *)groupAnimation:(NSRect)frame {
        CAAnimationGroup *group = [CAAnimationGroup animation];
        group.animations = [NSArray arrayWithObjects:
                            [self frameAnimation:frame],
                            [self rotationAnimation], nil];
        group.duration = 1.0f;
        group.autoreverses = YES;
        return group;
    }

    - (id)initWithFrame:(NSRect)rect {
    ...
            NSDictionary *animations = [NSDictionary
    dictionaryWithObjectsAndKeys:
                                        [self groupAnimation:[view
    frame]], @"frameRotation",
                                        nil];
    ...
            [view setAnimations:animations];
    ...
    }

    ...
    - (void)someEventMethod {
            // since the animation auto reverses this works fine (if it
    did not auto revers we'd
    //need to make sure that final rotation angle matched what is in the
    animation or we'd get jumpy movement)
            [[movingView animator] setFrameRotation:[movingView
    frameRotation]];
    }

    I you should attach your keyframe animation with a CGPath to the
    position property and a basic animation to the zPosition. Then you can
    put both in a group then attach the group to the zPosition. Then when
    you set the zPosition for the layer it will animate both properties.

    Some stuff to be aware of just in case you've not messed with groups
    before;
    - the animations you put in the group have to be tied to the property
    they will be animating (i.e. use animationWithKeyPath: instead of
    animation)
    - be aware that the final zPosition that you set should match the
    final position of the zPosition animation

    I have been able to animate the size of a view and a layer with a
    CGPath, the x values mapped to the width and y values to the height. I
    could not find the code right now but it was the same kind of thing.
    All i had to do was tie the keyframe animation to the frameSize
    property.

    HTH,

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

    > Hi List,
    >
    > I'm trying to animate X and Z on a curve (rotating image a bit like
    > front row does). I can get the position correctly and have it linearly
    > animated from one position to the other, but i'd rather have it curve
    > a bit before since it would feel more natural than a straight line.
    >
    > I thought the easiest way would be to use CAKeyframeAnimation and give
    > it a CGPath to follow. But it feels like that only works for animating
    > the position attribute or at least only for CGPoint attributes. Is
    > that the case ?
    >
    > So I tried creating my own CGPoint and have it set the position and
    > zPosition. But my new attribute does not get animated. Not even the
    > default basic animation. What needs to be done for a property of a
    > subclass of CALayer to be animatable ?
    >
    > Thanks.
    > Bertrand.
  • CAAnimationGroup would solve half of the issue. The problem is that I
    need the CGPath to affect both X and Z. So I guess I either have to
    create a new attribute with those 2, or there is away for CGPath to
    affect a 1d attribute

    2007/11/19, Bill Dudney <bdudney...>:
    > Hi Bertrand,
    >
    > If I understand correctly you want a CAAnimationGroup to get your
    > position and zPosition properties to animate at the same time (I've
    > only done this on a layer backed view myself but it should work).
    >
    > Here is the basic code that I'm using;
    >
    > - (CAAnimation *)frameAnimation:(NSRect)aniFrame {
    > CAKeyframeAnimation *frameAnimation = [CAKeyframeAnimation
    > animationWithKeyPath:@"frame"];
    > NSRect start = aniFrame;
    > NSRect end = NSInsetRect(aniFrame, -NSWidth(start) * 0.50, -
    > NSHeight(start) * 0.50);
    > frameAnimation.values = [NSArray arrayWithObjects:
    > [NSValue valueWithRect:start],
    > [NSValue valueWithRect:end], nil];
    > return frameAnimation;
    > }
    >
    > - (CABasicAnimation *)rotationAnimation {
    > CABasicAnimation *rotation = [CABasicAnimation
    > animationWithKeyPath:@"frameRotation"];
    > rotation.fromValue = [NSNumber numberWithFloat:0.0f];
    > rotation.toValue = [NSNumber numberWithFloat:45.0f];
    > return rotation;
    > }
    >
    > - (CAAnimationGroup *)groupAnimation:(NSRect)frame {
    > CAAnimationGroup *group = [CAAnimationGroup animation];
    > group.animations = [NSArray arrayWithObjects:
    > [self frameAnimation:frame],
    > [self rotationAnimation], nil];
    > group.duration = 1.0f;
    > group.autoreverses = YES;
    > return group;
    > }
    >
    > - (id)initWithFrame:(NSRect)rect {
    > ...
    > NSDictionary *animations = [NSDictionary
    > dictionaryWithObjectsAndKeys:
    > [self groupAnimation:[view
    > frame]], @"frameRotation",
    > nil];
    > ...
    > [view setAnimations:animations];
    > ...
    > }
    >
    > ...
    > - (void)someEventMethod {
    > // since the animation auto reverses this works fine (if it
    > did not auto revers we'd
    > //need to make sure that final rotation angle matched what is in the
    > animation or we'd get jumpy movement)
    > [[movingView animator] setFrameRotation:[movingView
    > frameRotation]];
    > }
    >
    > I you should attach your keyframe animation with a CGPath to the
    > position property and a basic animation to the zPosition. Then you can
    > put both in a group then attach the group to the zPosition. Then when
    > you set the zPosition for the layer it will animate both properties.
    >
    > Some stuff to be aware of just in case you've not messed with groups
    > before;
    > - the animations you put in the group have to be tied to the property
    > they will be animating (i.e. use animationWithKeyPath: instead of
    > animation)
    > - be aware that the final zPosition that you set should match the
    > final position of the zPosition animation
    >
    > I have been able to animate the size of a view and a layer with a
    > CGPath, the x values mapped to the width and y values to the height. I
    > could not find the code right now but it was the same kind of thing.
    > All i had to do was tie the keyframe animation to the frameSize
    > property.
    >
    > HTH,
    >
    > -bd-
    > http://bill.dudney.net/roller/objc
    >
    >> Hi List,
    >>
    >> I'm trying to animate X and Z on a curve (rotating image a bit like
    >> front row does). I can get the position correctly and have it linearly
    >> animated from one position to the other, but i'd rather have it curve
    >> a bit before since it would feel more natural than a straight line.
    >>
    >> I thought the easiest way would be to use CAKeyframeAnimation and give
    >> it a CGPath to follow. But it feels like that only works for animating
    >> the position attribute or at least only for CGPoint attributes. Is
    >> that the case ?
    >>
    >> So I tried creating my own CGPoint and have it set the position and
    >> zPosition. But my new attribute does not get animated. Not even the
    >> default basic animation. What needs to be done for a property of a
    >> subclass of CALayer to be animatable ?
    >>
    >> Thanks.
    >> Bertrand.

    >
  • Ah I see what you are getting at.

    I think you could do some 'clever coding' to get the path to effect z
    and x but I think the group would be better and simpler. Just make
    your CGPath with a constant y.

    HTH,

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

    On Nov 20, 2007, at 4:05 AM, Bertrand Landry-Hetu wrote:

    > CAAnimationGroup would solve half of the issue. The problem is that I
    > need the CGPath to affect both X and Z. So I guess I either have to
    > create a new attribute with those 2, or there is away for CGPath to
    > affect a 1d attribute
    >
    > 2007/11/19, Bill Dudney <bdudney...>:
    >> Hi Bertrand,
    >>
    >> If I understand correctly you want a CAAnimationGroup to get your
    >> position and zPosition properties to animate at the same time (I've
    >> only done this on a layer backed view myself but it should work).
    >>
    >> Here is the basic code that I'm using;
    >>
    >> - (CAAnimation *)frameAnimation:(NSRect)aniFrame {
    >> CAKeyframeAnimation *frameAnimation = [CAKeyframeAnimation
    >> animationWithKeyPath:@"frame"];
    >> NSRect start = aniFrame;
    >> NSRect end = NSInsetRect(aniFrame, -NSWidth(start) * 0.50, -
    >> NSHeight(start) * 0.50);
    >> frameAnimation.values = [NSArray arrayWithObjects:
    >> [NSValue valueWithRect:start],
    >> [NSValue valueWithRect:end], nil];
    >> return frameAnimation;
    >> }
    >>
    >> - (CABasicAnimation *)rotationAnimation {
    >> CABasicAnimation *rotation = [CABasicAnimation
    >> animationWithKeyPath:@"frameRotation"];
    >> rotation.fromValue = [NSNumber numberWithFloat:0.0f];
    >> rotation.toValue = [NSNumber numberWithFloat:45.0f];
    >> return rotation;
    >> }
    >>
    >> - (CAAnimationGroup *)groupAnimation:(NSRect)frame {
    >> CAAnimationGroup *group = [CAAnimationGroup animation];
    >> group.animations = [NSArray arrayWithObjects:
    >> [self frameAnimation:frame],
    >> [self rotationAnimation], nil];
    >> group.duration = 1.0f;
    >> group.autoreverses = YES;
    >> return group;
    >> }
    >>
    >> - (id)initWithFrame:(NSRect)rect {
    >> ...
    >> NSDictionary *animations = [NSDictionary
    >> dictionaryWithObjectsAndKeys:
    >> [self groupAnimation:[view
    >> frame]], @"frameRotation",
    >> nil];
    >> ...
    >> [view setAnimations:animations];
    >> ...
    >> }
    >>
    >> ...
    >> - (void)someEventMethod {
    >> // since the animation auto reverses this works fine (if it
    >> did not auto revers we'd
    >> //need to make sure that final rotation angle matched what
    >> is in the
    >> animation or we'd get jumpy movement)
    >> [[movingView animator] setFrameRotation:[movingView
    >> frameRotation]];
    >> }
    >>
    >> I you should attach your keyframe animation with a CGPath to the
    >> position property and a basic animation to the zPosition. Then you
    >> can
    >> put both in a group then attach the group to the zPosition. Then when
    >> you set the zPosition for the layer it will animate both properties.
    >>
    >> Some stuff to be aware of just in case you've not messed with groups
    >> before;
    >> - the animations you put in the group have to be tied to the property
    >> they will be animating (i.e. use animationWithKeyPath: instead of
    >> animation)
    >> - be aware that the final zPosition that you set should match the
    >> final position of the zPosition animation
    >>
    >> I have been able to animate the size of a view and a layer with a
    >> CGPath, the x values mapped to the width and y values to the
    >> height. I
    >> could not find the code right now but it was the same kind of thing.
    >> All i had to do was tie the keyframe animation to the frameSize
    >> property.
    >>
    >> HTH,
    >>
    >> -bd-
    >> http://bill.dudney.net/roller/objc
    >>
    >>> Hi List,
    >>>
    >>> I'm trying to animate X and Z on a curve (rotating image a bit like
    >>> front row does). I can get the position correctly and have it
    >>> linearly
    >>> animated from one position to the other, but i'd rather have it
    >>> curve
    >>> a bit before since it would feel more natural than a straight line.
    >>>
    >>> I thought the easiest way would be to use CAKeyframeAnimation and
    >>> give
    >>> it a CGPath to follow. But it feels like that only works for
    >>> animating
    >>> the position attribute or at least only for CGPoint attributes. Is
    >>> that the case ?
    >>>
    >>> So I tried creating my own CGPoint and have it set the position and
    >>> zPosition. But my new attribute does not get animated. Not even the
    >>> default basic animation. What needs to be done for a property of a
    >>> subclass of CALayer to be animatable ?
    >>>
    >>> Thanks.
    >>> Bertrand.

    >>
previous month november 2007 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    
Go to today