I have a simple animation that repeats, but between the repeats (after each 5 frames cycle) there is a small lag of about 200 ms, and the transition is not smooth.
Why?
- (void)Animation
{
imageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"walkcycle-01.png"],
[UIImage imageNamed:#"walkcycle-02.png"],
[UIImage imageNamed:#"walkcycle-03.png"],
[UIImage imageNamed:#"walkcycle-04.png"],
[UIImage imageNamed:#"walkcycle-05.png"], nil];
imageView.animationDuration = 1.4;
[imageView setAnimationRepeatCount: 0];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[imageView startAnimating];
}
I'm assuming that, because you have the repeat count set to 0, you're simply calling Animation multiple times.
If so, it may be that creating the animation is CPU intensive, therefore causing it to take a few seconds in between to build the animation. I'd recommend using a repeat instead of making it over and over.
Did you try to set the AnimationRepeatCount to INFINITY? Also you can try -1
[UIView setAnimationRepeatCount: INFINITY];
or
[UIView setAnimationRepeatCount: -1];
Related
I have an UIImageView that I am moving around a circle with CGAffineTransformRotate. Works great! But when the user press a stop bottom I would like to the the actual x- / y- position of the UIImageView. So far I am always getting the original x- / y- values from when the UIImageView was created.
Is there a way to get the actual position, when the user stopped the rotation?
I have found the solution and share it in case someone is running a similar case:
From UIBezierPath I use the bounds information and this give me the position where the UIImageView stopped. Here the code:
UIBezierPath *path = [[UIBezierPath alloc] init];
[path addArcWithCenter:CGPointMake(iMiddleX, iMiddleY) radius:flR startAngle:degreesToRadians(flDegrees-0.01) endAngle:degreesToRadians(flDegrees) clockwise:YES];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.repeatCount = 1;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
pathAnimation.duration = 1.0;
pathAnimation.path = path.CGPath;
NSInteger iX = path.bounds.origin.x;
NSInteger iY = path.bounds.origin.y;
This is the constructor of my NSWindow subclass called FullScreenWindow :
- (id)initWithScreen:(NSScreen *)s {
NSRect contentRect = [s frame];
self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO
screen:s];
if (self) {
[self setCollectionBehavior:NSWindowCollectionBehaviorStationary|
NSWindowCollectionBehaviorCanJoinAllSpaces|
NSWindowCollectionBehaviorIgnoresCycle];
[self setReleasedWhenClosed:YES];
[self setBackgroundColor:[NSColor greenColor]];
[self setAlphaValue:1.0];
[self setOpaque:NO];
[self setLevel:NSMainMenuWindowLevel-1];
}
return self;
}
I wanna add such an NSWindow to every display in [NSScreen screens] but when I connect a second display, the windows only display the right way if I set origin.x of contentRect to -1440 for the first display (and 0 for the second one). When I get origin.x values of the frames of the NSScreen instances it returns 0 for the first display and 1440 for the second one. Why are these coordinates shifted?
One of the [NSScreen screens] will have (0, 0) as origin.
Now imagine 2 axes: Y goes up from (0, 0) and X goes to the right.
All other screens will have coordinates with this coordinate system and screen.frame.origin will represent bottom left corner.
I could not find this in the documentation, so I found this experimenting with displays arrangement.
I had this picture with two monitors: main one 1366x768, secondary 1680x1050, aligned to the top.
I tried also different arrangements, moving #1 around #0, and my hypothesis was always correct.
Is there any way to do things the "short and easy" way like below? The curve appears to still use EaseOut.
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView animateWithDuration:0.5 animations:^{
// ... do stuff here
}];
You are mixing two different kinds of UIView-animations. You should be using something like this either of these:
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
// ... do stuff here
} completion:NULL];
This came from the newer block-based UIView-animation API. The first line, on the other hand, is part of the older UIView animation API that looks like this:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
// ... do stuff here
[UIView commitAnimations];
They do the same thing and you can use either (though Apple recommends the block-based API since it is easier/cleaner to do callbacks after the animation finishes).
You can do it using Core Animation , CAKeyFrameAnimation to define the curve points. See this tutorial: http://nachbaur.com/blog/core-animation-part-4
Let's take curve points p1, p2, p3, p4 and p5, & find mid point for each pair of adjacent points. Label m1 as the mid point for p1 and p2. Similarly for m2, m3, m4.
Add quad curve to point m2 with p2 as a control point.
Add quad curve to point m3 with p3 as a control point.
Add quad curve to point m4 with p4 as a control point.
Code:
CGFloat screenHeight = self.view.frame.size.height;
CGFloat screenWidth = self.view.frame.size.width;
UIView *aniView = [[UIView alloc] initWithFrame:CGRectMake(50, screenHeight, 50, 50)];
[aniView setBackgroundColor:[UIColor redColor]];
aniView.layer.cornerRadius = 25.0;
[self.view addSubview:aniView];
UIBezierPath *movePath = [UIBezierPath bezierPath];
[movePath moveToPoint:aniView.center];
[movePath addQuadCurveToPoint:CGPointMake(screenWidth-50,screenHeight-50)
controlPoint:CGPointMake(screenWidth/2,screenHeight-150)];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = YES;
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations = [NSArray arrayWithObjects:moveAnim, nil];
animGroup.duration = 2.0;
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
[aniView.layer removeAllAnimations];
[aniView removeFromSuperview];
}];
[aniView.layer addAnimation:animGroup forKey:nil];
} [CATransaction commit];
Copy past above code into some method and try calling the method...
In the cocos2d programming guide there is the following code:
CGSize s = [[CCDirector sharedDirector] winSize];
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:#"grossini_dance_01.png"];
sprite.position = ccp( s.width/2-80, s.height/2);
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"animations/grossini.png"];
[batchNode addChild:sprite];
[self addChild:batchNode];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < 15; i++) {
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"grossini_dance_%02d.png",i]];
[animFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithName:#"dance" delay:0.2f frames:animFrames];
[sprite runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO] ]];
It adds a simple animation in the form of an array of frames and adds the sprite which will animate these frames into a CCSpriteBatchNode. My question is: will batch drawing a single animated sprite be any more efficient than not using batching at all? Since there is only one frame drawn at each draw and only one object, I would think not. The only benefit I think would be if you added more than one object - so that they could be drawn at their frame coordinates from the same texture in a single draw. Is my reasoning correct?
Thanks to replies here:
http://www.cocos2d-iphone.org/forum/topic/29354?replies=3#post-144515
At least one person has confirmed it has no benefit whatsoever with one object, but may reduce performance slightly from the added complexity.
The Leaks instrument is sounding the alarm on some code, but I don't know how to address the leak without crashing the app. Here's some code summarizing my approach, written some time ago and clearly in need of rethinking:
labels = [[NSMutableArray alloc] init];
for(int i = 0; i < 10; i++) {
// calculate x and y...
label = [[UILabel alloc] initWithFrame:CGRectMake(x, y, 70, 15)];
// customize label...
[labels addObject:label];
[label release];
[self addSubview:[labels objectAtIndex:i]];
}
Why bother with the labels NSMutableArray? Later, in other methods, I need to change the alpha of the labels, and it's convenient to be able to say
[[labels objectAtIndex:num] setAlpha:0.5];
I believe the leak occurs because labels doesn't get dealloc'ed during the normal app lifecycle, only when the superview is dealloc'd at quit.
Help!
Thanks.
It's probably happening because you're not dealloc'ing the labels array. What about releasing the labels array after the for loop, then using .tag to set the label on the UIView and find the label later via the .tag using viewWithTag to setAlpha?
labels = [[NSMutableArray alloc] init];
for(int i = 0; i < 10; i++) {
// calculate x and y...
label = [[UILabel alloc] initWithFrame:CGRectMake(x, y, 70, 15)];
label.tag = 100;
// customize label...
[labels addObject:label];
[label release];
[self addSubview:[labels objectAtIndex:i]];
}
[labels removeAllObjects];
[labels release];
Then later
(UILabel*) [[self.view viewWithTag:100] setAlpha:0.5];