Re: problems with CAAnimation - SOLVED (kinda)
-
Hi, I've used jQuery, but I don't understand the relevance or what you
mean?
On 19 Mar 2009, at 22:30, mm w wrote:> you should really create a html page and play for instance with jQuery
> to understand how those mechanisms/API have been designed, and when
> you will
> understand what you are doing you will welcome to come again
>
> Cheers!
>
> On Thu, Mar 19, 2009 at 3:26 PM, Memo Akten <memo...> wrote:
>> Hi Matt, thanks for lengthy reply. At this point, I"ve only tried
>> the first
>> part, and I cannot get it to use the time I'm supplying in the
>> animation,
>> basically its just doing an implicit animation not explicit. It
>> doesn't
>> matter whether I setValue before or after the addAnimation.
>>
>> Actually I ended up writing the generic code below. If I apply the
>> CAAnimationGroup as a group (i.e. bApplyIndividually = NO), then it
>> doesn't
>> work at all for some reason, the values from the
>> layer.presentationLayer do
>> not represent what I am seeing so a lot of snapping going on if I
>> apply
>> animations before the previous one is finished. If I only use the
>> CAAnimationGroup as a glorified array and apply all animations
>> individually
>> then all my animations are applied correctly. So I think this is my
>> solution. I do find it strange that I had to resort to this
>> (writing my own
>> AnimationGroup!), and this behavior is not built in. Thanks for all
>> the tips
>> and help.
>>
>> (P.S. this assumes that all the animations in the CAAnimationGroup
>> are
>> CABasicAnimations).
>>
>>
>> void applyBasicAnimation(CALayer *layer, CABasicAnimation
>> *animation, BOOL
>> bApply) {
>> animation.fromValue =
>> [layer.presentationLayer valueForKeyPath:animation.keyPath];
>> animation.removedOnCompletion = NO;
>> animation.fillMode =
>> kCAFillModeBoth;
>> NSLog(@"applyBasicAnimation forLayer:%@ key:%@ currentValue:
>> %@",
>> layer.name, animation.keyPath, animation.fromValue);
>> if(bApply) [layer addAnimation:animation
>> forKey:animation.keyPath];
>> }
>>
>> void applyAnimationGroup(CALayer *layer, CAAnimationGroup
>> *animationGroup,
>> NSString* key, BOOL bApplyIndividually) {
>> animationGroup.removedOnCompletion = NO;
>> animationGroup.fillMode =
>> kCAFillModeBoth;
>> for(id animation in animationGroup.animations)
>> applyBasicAnimation(layer, animation, bApplyIndividually);
>> if(!bApplyIndividually) [layer addAnimation:animationGroup
>> forKey:key];
>> }
>>
>>
>> On 19 Mar 2009, at 18:07, Matt Long wrote:
>>
>>> I'll address the issue with the animation ignoring your duration
>>> first.
>>> Try placing your addAnimation call before the setValue:forKeyPath.
>>> Let me
>>> know if that works. Also, you will *need* to specify a fromValue
>>> in your
>>> animation. If you want the current value (in the case where an
>>> animation is
>>> already running), get it from the presentationLayer, e.g. [[layer
>>> presentationLayer] valueForKeyPath@"transform.scale"]; This is the
>>> "in-flight" value.
>>>
>>> Now let me try to clarify what I mean with the derived layer. Say
>>> you've
>>> declared a layer called RolloverLayer that inherits from CALayer.
>>> Calling
>>> animationForKey will return the default animation for the keyPath
>>> you
>>> specify in the key. If you override it, *you* determine what
>>> animation to
>>> use. It would look something like this:
>>>
>>> - (CAAnimation *)animationForKey:(NSString *)key
>>> {
>>> if ([key isEqualToString:@"transform.scale"] )
>>> {
>>> CABasicAnimation *growAnimation = [[CABasicAnimation
>>> animationWithKeyPath:@"transform.scale"] retain];
>>> growAnimation.duration = 5; // very slow
>>> // Need from value here
>>> growAnimation.fromValue = [[self presentationLayer]
>>> valueForKeyPath:@"transform.scale"];
>>> growAnimation.toValue = [[[CardManager instance] config]
>>> objectForKey:@"cardHoverScale"];
>>> growAnimation.timingFunction = [CAMediaTimingFunction
>>> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
>>> return growAnimation;
>>> }
>>> else if ([key isEqualToString:@"position"])
>>> {
>>> CABasicAnimation *postiionAnimation = [CABasicAnimation
>>> animationWithKeyPath:@"position"];
>>> positionAnimation.fromValue = [[self presentationLayer]
>>> position];
>>> positionAnimation.toValue = // etc...
>>>
>>> }
>>> // .........
>>> else
>>> {
>>> return [super animationForKey:key];
>>> }
>>> }
>>>
>>> Now, when you have one of your derived layers in use, you can do
>>> this:
>>>
>>> // Assuming it's tied to a button or something
>>> - (IBAction)animate:(id)sender
>>> {
>>> // rolloverLayer is a RolloverLayer ivar
>>> [rolloverLayer setValue:[[[CardManager instance] config]
>>> objectForKey:@"cardHoverScale"] forKeyPath:@"transform.scale"];
>>> [rolloverLayer setPosition:CGPointMake(x,y)];
>>> // etc.
>>> }
>>>
>>> Your overridden animationForKey will get called to get the proper
>>> animation.
>>>
>>> HTH,
>>>
>>> -Matt
>>>
>>> p.s. if you want to know when an animation has completed, set the
>>> layer's
>>> delegate to your app delegate and then implement -
>>> (void)animationDidStop:(CAAnimation *)theAnimation finished:
>>> (BOOL)flag . The
>>> flag field tells you whether or not it stopped by interruption or
>>> by run
>>> completion. YES means it completed its run, NO means it was
>>> interrupted.
>>>
>>>
>>> On Mar 19, 2009, at 11:09 AM, Memo Akten wrote:
>>>
>>>> Hi Matt, yea it is a bit complex, but it seems to me that what I am
>>>> trying to do is actually quite simple:
>>>>
>>>> - when I rollover a layer, it animates position, scale, rotation
>>>> and
>>>> alpha.
>>>> - when I rollout, it animates back.
>>>> - if I rollover, then midanimation, rollout again, it should
>>>> animate back
>>>> to original position *from where it was at the moment I rolled
>>>> out*, NOT
>>>> snapping to the hover position (which is why I can't use
>>>> FromValues).
>>>>
>>>> I also would like the animation to be EaseInEaseOut and know when
>>>> the
>>>> animation is complete - which is why I'm using CAAnimation, so I
>>>> can use
>>>> delegate - instead of using implicit animation.
>>>>
>>>>
>>>> Going back to what you were saying, I'm afraid I don't full
>>>> understand.
>>>> So I extend CALayer? How would I use animationForKey? Does that
>>>> not only
>>>> return the animation for a given arbitrary key?
>>>>
>>>> Also I tried the code below, and unfortunately the animation
>>>> happened
>>>> very quickly, not 5 seconds at all...
>>>>
>>>> growAnimation = [[CABasicAnimation
>>>> animationWithKeyPath:@"transform.scale"] retain];
>>>> growAnimation.duration = 5; // very slow
>>>> growAnimation.toValue = [[[CardManager instance] config]
>>>> objectForKey:@"cardHoverScale"];
>>>> growAnimation.timingFunction = [CAMediaTimingFunction
>>>> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
>>>>
>>>> [rootLayer setValue:[[[CardManager instance] config]
>>>> objectForKey:@"cardHoverScale"] forKeyPath:@"transform.scale"];
>>>> [rootLayer addAnimation:growAnimation forKey:@"transform.scale"];
>>>>
>>>>
>>>>
>>>
>>
>
>
>
> --
> -mmw -
your design simply sucks, you don't understand the library
I cannot help you on this, I am not Jesus and I cannot save all people who
are pretending to program, once again I did complex design with CA related API,
and I have never been stuck in this kind of issue, so I let you think,
nobody can solve
your issue you took the wrong way
Cheers!
On Thu, Mar 19, 2009 at 4:05 PM, Memo Akten <memo...> wrote:> Hi, I've used jQuery, but I don't understand the relevance or what you mean?
>
> On 19 Mar 2009, at 22:30, mm w wrote:
>
>> you should really create a html page and play for instance with jQuery
>> to understand how those mechanisms/API have been designed, and when you
>> will
>> understand what you are doing you will welcome to come again
>>
>> Cheers!
>>
>> On Thu, Mar 19, 2009 at 3:26 PM, Memo Akten <memo...> wrote:
>>>
>>> Hi Matt, thanks for lengthy reply. At this point, I"ve only tried the
>>> first
>>> part, and I cannot get it to use the time I'm supplying in the animation,
>>> basically its just doing an implicit animation not explicit. It doesn't
>>> matter whether I setValue before or after the addAnimation.
>>>
>>> Actually I ended up writing the generic code below. If I apply the
>>> CAAnimationGroup as a group (i.e. bApplyIndividually = NO), then it
>>> doesn't
>>> work at all for some reason, the values from the layer.presentationLayer
>>> do
>>> not represent what I am seeing so a lot of snapping going on if I apply
>>> animations before the previous one is finished. If I only use the
>>> CAAnimationGroup as a glorified array and apply all animations
>>> individually
>>> then all my animations are applied correctly. So I think this is my
>>> solution. I do find it strange that I had to resort to this (writing my
>>> own
>>> AnimationGroup!), and this behavior is not built in. Thanks for all the
>>> tips
>>> and help.
>>>
>>> (P.S. this assumes that all the animations in the CAAnimationGroup are
>>> CABasicAnimations).
>>>
>>>
>>> void applyBasicAnimation(CALayer *layer, CABasicAnimation *animation,
>>> BOOL
>>> bApply) {
>>> ÃÂ ÃÂ ÃÂ animation.fromValue ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ =
>>> [layer.presentationLayer valueForKeyPath:animation.keyPath];
>>> ÃÂ ÃÂ ÃÂ animation.removedOnCompletion ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ = NO;
>>> ÃÂ ÃÂ ÃÂ animation.fillMode ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ =
>>> kCAFillModeBoth;
>>> ÃÂ ÃÂ ÃÂ NSLog(@"applyBasicAnimation forLayer:%@ key:%@ currentValue:%@",
>>> layer.name, animation.keyPath, animation.fromValue);
>>> ÃÂ ÃÂ ÃÂ if(bApply) [layer addAnimation:animation forKey:animation.keyPath];
>>> }
>>>
>>> void applyAnimationGroup(CALayer *layer, CAAnimationGroup
>>> *animationGroup,
>>> NSString* key, BOOL bApplyIndividually) {
>>> ÃÂ ÃÂ ÃÂ animationGroup.removedOnCompletion ÃÂ ÃÂ ÃÂ = NO;
>>> ÃÂ ÃÂ ÃÂ animationGroup.fillMode ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ = kCAFillModeBoth;
>>> ÃÂ ÃÂ ÃÂ for(id animation in animationGroup.animations)
>>> applyBasicAnimation(layer, animation, bApplyIndividually);
>>> ÃÂ ÃÂ ÃÂ if(!bApplyIndividually) [layer addAnimation:animationGroup
>>> forKey:key];
>>> }
>>>
>>>
>>> On 19 Mar 2009, at 18:07, Matt Long wrote:
>>>
>>>> I'll address the issue with the animation ignoring your duration first.
>>>> Try placing your addAnimation call before the setValue:forKeyPath. Let
>>>> me
>>>> know if that works. Also, you will *need* to specify a fromValue in your
>>>> animation. If you want the current value (in the case where an animation
>>>> is
>>>> already running), get it from the presentationLayer, e.g. [[layer
>>>> presentationLayer] valueForKeyPath@"transform.scale"]; This is the
>>>> "in-flight" value.
>>>>
>>>> Now let me try to clarify what I mean with the derived layer. Say you've
>>>> declared a layer called RolloverLayer that inherits from CALayer.
>>>> Calling
>>>> animationForKey will return the default animation for the keyPath you
>>>> specify in the key. If you override it, *you* determine what animation
>>>> to
>>>> use. It would look something like this:
>>>>
>>>> - (CAAnimation *)animationForKey:(NSString *)key
>>>> {
>>>> ÃÂ if ([key isEqualToString:@"transform.scale"] )
>>>> ÃÂ {
>>>> ÃÂ ÃÂ ÃÂ CABasicAnimation *growAnimation = [[CABasicAnimation
>>>> animationWithKeyPath:@"transform.scale"] retain];
>>>> ÃÂ ÃÂ ÃÂ growAnimation.duration = 5; // very slow
>>>> ÃÂ ÃÂ ÃÂ // Need from value here
>>>> ÃÂ ÃÂ ÃÂ growAnimation.fromValue = [[self presentationLayer]
>>>> valueForKeyPath:@"transform.scale"];
>>>> ÃÂ ÃÂ ÃÂ growAnimation.toValue = [[[CardManager instance] config]
>>>> objectForKey:@"cardHoverScale"];
>>>> ÃÂ ÃÂ ÃÂ growAnimation.timingFunction = [CAMediaTimingFunction
>>>> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
>>>> ÃÂ ÃÂ ÃÂ return growAnimation;
>>>> ÃÂ }
>>>> ÃÂ else if ([key isEqualToString:@"position"])
>>>> ÃÂ {
>>>> ÃÂ ÃÂ ÃÂ CABasicAnimation *postiionAnimation = [CABasicAnimation
>>>> animationWithKeyPath:@"position"];
>>>> ÃÂ ÃÂ ÃÂ positionAnimation.fromValue = [[self presentationLayer] position];
>>>> ÃÂ ÃÂ ÃÂ positionAnimation.toValue = // etc...
>>>>
>>>> ÃÂ }
>>>> ÃÂ // .........
>>>> ÃÂ else
>>>> ÃÂ {
>>>> ÃÂ ÃÂ ÃÂ return [super animationForKey:key];
>>>> ÃÂ }
>>>> }
>>>>
>>>> Now, when you have one of your derived layers in use, you can do this:
>>>>
>>>> // Assuming it's tied to a button or something
>>>> - (IBAction)animate:(id)sender
>>>> {
>>>> ÃÂ // rolloverLayer is a RolloverLayer ivar
>>>> ÃÂ [rolloverLayer setValue:[[[CardManager instance] config]
>>>> objectForKey:@"cardHoverScale"] forKeyPath:@"transform.scale"];
>>>> ÃÂ [rolloverLayer setPosition:CGPointMake(x,y)];
>>>> ÃÂ // etc.
>>>> }
>>>>
>>>> Your overridden animationForKey will get called to get the proper
>>>> animation.
>>>>
>>>> HTH,
>>>>
>>>> -Matt
>>>>
>>>> p.s. if you want to know when an animation has completed, set the
>>>> layer's
>>>> delegate to your app delegate and then implement -
>>>> (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag .
>>>> The
>>>> flag field tells you whether or not it stopped by interruption or by run
>>>> completion. YES means it completed its run, NO means it was interrupted.
>>>>
>>>>
>>>> On Mar 19, 2009, at 11:09 AM, Memo Akten wrote:
>>>>
>>>>> Hi Matt, yea it is a bit complex, but it seems to me that what I am
>>>>> trying to do is actually quite simple:
>>>>>
>>>>> - when I rollover a layer, it animates position, scale, rotation and
>>>>> alpha.
>>>>> - when I rollout, it animates back.
>>>>> - if I rollover, then midanimation, rollout again, it should animate
>>>>> back
>>>>> to original position *from where it was at the moment I rolled out*,
>>>>> NOT
>>>>> snapping to the hover position (which is why I can't use FromValues).
>>>>>
>>>>> I also would like the animation to be EaseInEaseOut and know when the
>>>>> animation is complete - which is why I'm using CAAnimation, so I can
>>>>> use
>>>>> delegate - instead of using implicit animation.
>>>>>
>>>>>
>>>>> Going back to what you were saying, I'm afraid I don't full understand.
>>>>> So I extend CALayer? How would I use animationForKey? Does that not
>>>>> only
>>>>> return the animation for a given arbitrary key?
>>>>>
>>>>> Also I tried the code below, and unfortunately the animation happened
>>>>> very quickly, not 5 seconds at all...
>>>>>
>>>>> growAnimation ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ = [[CABasicAnimation
>>>>> animationWithKeyPath:@"transform.scale"] retain];
>>>>> growAnimation.duration ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ = 5; // very slow
>>>>> growAnimation.toValue ÃÂ ÃÂ ÃÂ ÃÂ ÃÂ = [[[CardManager instance] config]
>>>>> objectForKey:@"cardHoverScale"];
>>>>> growAnimation.timingFunction ÃÂ ÃÂ = [CAMediaTimingFunction
>>>>> functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
>>>>>
>>>>> [rootLayer setValue:[[[CardManager instance] config]
>>>>> objectForKey:@"cardHoverScale"] forKeyPath:@"transform.scale"];
>>>>> [rootLayer addAnimation:growAnimation forKey:@"transform.scale"];
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>
>>
>>
>> --
>> -mmw
>
>
--
-mmw -
On 20/03/2009, at 10:39 AM, mm w wrote:> your design simply sucks, you don't understand the library
> I cannot help you on this, I am not Jesus and I cannot save all
> people who
> are pretending to program, once again I did complex design with CA
> related API,
> and I have never been stuck in this kind of issue, so I let you think,
> nobody can solve
> your issue you took the wrong way
There is absolutely no call for this sort of language. If you are
unable to help, you are not obliged to reply. Mounting personal
attacks on people is not helpful in any way - do you think anyone is
going to be impressed by your supposed "superior" knowledge with this
attitude? No-one is asking or expecting you to "save" them, so quit
with the God complex, hmmm?
There is a wide spread of expertise on this list, including many
beginners. Attacking them with phrases such as "pretending to program"
is not going to assist them and just makes you look like a dickhead.
Not only that, but where you have made an attempt to offer actual
advice, it has been hilariously wrong, which completely undermines
your self-made claim of being such a clued-up programmer. If you want
respect, earn it kiddo.
--Graham


