Unpredictable crash due to UIView animations - ios

I have made a custom activity indicator to use in a project. I rotate a static loader image for that.
- (void) rotate {
lastInstance++;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(rotate)];
[UIView setAnimationDuration:0.1];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
spinnerImageView.layer.transform = CATransform3DMakeRotation(M_PI*(lastInstance%10)/5, 0.0, 0.0, 1.0);
[UIView commitAnimations];
}
The spinnerimageview is contained within a superview container, and it bears the static loader image. It works fine, except for crashing unpredictably without any error messages.

Looks like you're stuck in a never ending recursion. How do you decide when to stop the rotation?
Each time the rotation animation completes it simply calls rotate again, with seemingly no end in sight.
The crash you are seeing is likely a stack overflow (how apt).
I'd suggest rethinking how to you decide whether the animation could continue.

Related

Flick a UIScrollView programmatically

When a user makes a flick gesture on a UIScrollView, the UIScrollView gets a momentum and starts moving, then slow down and finally stop.
But how can I make this happen programmatically? I mean without a finger flicking, the UIScrollView just start moving automatically and then slow down to a speed of 0.
In my app I have made my UIScrollView unlike a normal UIScrollView (say it looks like a roller), so I want make a hint to the user that he can scroll it (and then everything get started!)
I have googled a lot but there seemed no way to solve my problem. The setContentOffset just couldn't make the natural "slow down and stop at somewhere ahead" effect.
Any idea would be appreciated.
Thanks in advance.
Try, something like this >
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDelay:.8];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:(abs(1-3)*0.3)];
self.myScroll.contentOffset = CGPointMake(0, 500);
[UIView commitAnimations];
It is not currently what you need, but you can customise this code, and may be all be ok)
or use this code>
[UIView animateWithDuration:2.
delay:0.3
usingSpringWithDamping:1.
initialSpringVelocity:7.
options:UIViewAnimationOptionCurveEaseInOut animations:^{
//Animations
self.myScroll.contentOffset = CGPointMake(0, 500);
}
completion:^(BOOL finished) {
//Completion Block
}];
I think it is like you want(animation with damping like swipe effect)

How do I move an image from the top of the screen to the bottom and have it stay there in Xcode / iOS?

I have been trying to build an entry effect for a logo to come from the top of the screen to the bottom and remain there when a new view loads in my application. I have seen all of the tutorials that use NSTimer to bounce an image but once my logo hits the bottom it needs to exit. I'm going to read up on animation block codes to see if my solution resides there.
Apologies I'm a new be and am very grateful for the assistance.
Set logo frame to top and then:
[UIView beginAnimations: #"moveLogo" context: nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
logoToMove.frame = CGRectMake( final frame at the bottom );
[UIView commitAnimations];
logoToMove is your logo, give it an outlet and hook it in xib.
So you will set the initial frame and in the animation - the final frame. The animation will do the rest of the job.
Change UIViewAnimationCurveLinear to a desired one if you don't like that. Also the duration to speed up or slow down the movement.
To remove the view at the end of your animation, the easiest way would be to use blocks :
logoToMove.frame = topRect;
[UIView animateWithDuration:duration
animations:^{
logoToMove.frame = bottomFrame;
}
completion:^(BOOL finished) {
[logoToMove removeFromSuperview];
}
];
Doing it like that gives you control over the animation and on what to do once it's finished in a single method

Reverse a CGAffineTransform rotation on a custom UIView with UIBezierPaths

I have a custom UIView. It initializes two rectangular UIBezierPaths, and in drawRect it simply fills these two paths.
This view is placed on a button. When the button is clicked, a rotation is applied to it inside an animateWithDuration block:
icon.transform = CGAffineTransformMakeRotation(M_PI*-0.25);
This works great.
When the button is clicked again, I am trying to make the view rotate back to it's original orientation (reverse the rotation). I have tried:
icon.transform = CGAffineTransformInvert(icon.transform);
icon.transform = CGAffineTransformMakeRotation(M_PI*0.25);
icon.transform = CGAffineTransformIdentity;
... and a number of other variations, but none of them seem to work. Instead, the view is distorted until it's no longer visible -- sorta stretched to nothing. Sometimes, reapplying the first transform brings it back but with other reversals it doesn't.
What am I doing wrong?
In ios the transform is always relative, so once transformation is done, the next transformation should be relative to the previous transformation. You can simply change the frame of the view and revert it back to normal on second button click. On even clicks you will have to revert back the frame. Implement the following code. You can use the block level code if you feel comfortable with it as it is the new norm.
int noOfClicks = 0;
-(IBAction)yourBtnAction:(id)sender
{
noOfClicks++;
if(noOfClicks %2 != 0)
{
[UIView beginAnimations:#"Rotate" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelegate:self];
CGRect frame=yourView.frame;
frame.origin.y+=20;
yourview.frame=frame;
[UIView commitAnimations];
}
else
{
[UIView beginAnimations:#"Rotate" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelegate:self];
CGRect frame=yourView.frame;
frame.origin.y-=20;
yourview.frame=frame;
[UIView commitAnimations];
}
}
If you don't want to make so many change you can use following to revert back but employing same logic:
[UIView beginAnimations:#"Rotate back" context:nil];
[UIView setAnimationDuration:1.0];
yourView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];

Choppy UIView animation

I use a UIView animation to randomly animate 5 squares (UIButtons) around the screen. Depending on a user selection, there are anywhere from 2 to 5 squares visible. When only 2 are visible, the other three's hidden values get set to YES, so they are actually still animating (right?), they just aren't visible. But when only 2 are visible, the animation is smooth, but when all five are visible, the animation gets choppy. I'm not really sure how to describe it, because the squares are still moving at the correct speed and moving to the correct points; the choppiness isn't terrible, just bad enough to be noticeable. Is there any way to get rid of it? This is the code I use to animate the squares:
Edit: changed animations to block:
[UIView animateWithDuration:animationSpeed
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
view.center = destPoint;
}
completion:^(BOOL finished){
if([view isEqual:squareThree])
[self moveBadGuys];
}
];
/*for(UIButton* button in squareArray) {
if(!shouldMove)
return;
[UIView beginAnimations:#"b" context:nil];
[UIView setAnimationDuration:animationSpeed];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
view.center = destPoint;
[UIView commitAnimations];
}*/
Edit: the view presenting this is the third in a stack of three UIViewController presented with
ViewController* controller = [[[ViewController alloc] init] autorelease];
[self presentModalViewController:controller animated:NO];
Does this way of presenting views eat up memory?
There are a few things that can cause this. It always comes down to how complex the content is. Also, simulator can be really bad about handling animation, so be sure you are testing on real hardware.
Are there large images on the buttons? Are the buttons casting shadows? Those things can slow it down.
Also- use block based animation. Not the old begin-commit methods.
Not exactly sure why it's slow, but have you tried nesting the thing differently?
if(!shouldMove)
return;
[UIView beginAnimations:#"b" context:nil];
[UIView setAnimationDuration:animationSpeed];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
for(UIButton* button in squareArray) {
view.center = destPoint;
}
[UIView commitAnimations];
does (almost - the logic is a bit different in the !shouldMove case, but that's a different story) the same, but in a cleaner way.

iOS: UIView animation, no animating happening

Having a puzzling problem. I have a universal app with a lot of shared code between the iPad and iPhone versions. There are different layouts in the nibs but essentially the same views and view hierarchy - one UIView used as a container for two sibling UITextViews.
UIView mainView with children:
UITextView passageTextView
UITextView notesTextView
One UITextView is hidden, the other visible.
The following is my code. The section commented out was my original animation attempt. This worked just as desired on the iPad, but not on the iPhone. The uncommented section is take 2, using the method recommended in the docs. The uncommented code does not work on either the iPad or iPhone - it hides/unhides my views but without any animation. If I add code to the completion block that also gets executed, so it's doing something, just not animating.
/*
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:mainView cache:YES];
passageTextView.hidden = YES;
notesTextView.hidden = NO;
[UIView commitAnimations];
*/
UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationTransitionFlipFromRight;
[UIView transitionWithView:mainView
duration:1.0
options:options
animations:^{ passageTextView.hidden = YES; notesTextView.hidden = NO; }
completion:NULL];
Edit: Still working on the problem, hoping someone has a suggestion.
Additional update
Figured out why the following was not working in the iPhone:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:mainView cache:YES];
passageTextView.hidden = YES;
notesTextView.hidden = NO;
[UIView commitAnimations];
I had neglected to wire the view to mainView in Interface Builder. Hours debugging and I just now thought to check that.
But, I still do not know why animation blocks are not working for either the iPhone or iPad. I have tried several approaches but I'm not getting any animation even though the show/hides are working.
I think you are using the wrong animation option.
Replace your second animation option by UIViewAnimationOptionTransitionFlipFromLeft (note the Option between Animation and Transition)
I believe that UIViewAnimationTransitionFlipFromLeft (which is what you have in your code) is a UIViewAnimationTransition not a UIViewAnimationOptions.

Resources