spin UIImageView with core animation - objective-c

I am trying to make something relatively simple, make a wheel spin 90degrees when the user touches a button, for the most part what I have done so far works the first time, but thereafter the image won't move. I want it to keep its new position and rotate 90degrees thereafter from the new position, I have
[UIView setAnimationBeginsFromCurrentState:YES];
but that doesn't seem to work
I added an NSTimer to "reset" the original image orientation, so that the wheel springs back to the original position and then rotates again when the user touches it. ... however this isn't really what I want.
Is there a way to make the image keep rotating 90degrees so four touches by the user would put the image back to its original position. Thanks for any help!!
here is the sample code
-(IBAction) rotatewheel:(id)sender {
[UIView setAnimationDuration:1];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationRepeatCount:1];
wheel.transform = CGAffineTransformMakeRotation(M_PI/4);
[UIView commitAnimations];
returnwheelTimer = [NSTimer scheduledTimerWithTimeInterval:1.1 target:self selector:#selector (returnwheel) userInfo:nil repeats:NO];
}
-(void) returnwheel {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationRepeatCount:1];
wheel.transform = CGAffineTransformMakeRotation(M_PI);
[UIView commitAnimations];
}

Instead of:
wheel.transform = CGAffineTransformMakeRotation(M_PI/4);
use
wheel.transform = CGAffineTransformRotate(wheel.transform,M_PI/4);
That way it will apply the new tranformation to the current one, instead of replacing it.

There are three easy ways to implement this.
1) Make your app in a game engine, such as Unity3D, rather than in XCode. Make an animation of the spinning wheel and script it to start on the button push. This is relatively simple to do and there are many good existing tutorials. I recommend using iGUI by Avaam Studios (I am not affiliated with them or biased in any way).
2) Create an NSObject with an array of photos and start a stop motion animation of the wheel spinning on the button push. A thread on this subject can be found here.
3) If you want the wheel to spin 90 degrees FROM its last location, so that it can be spun full circle (36) after four clicks, then a different approach is needed. I recommend making the button be replaced with a different, identical one each time it is pushed. That way you do not need to do the math on the number of pushes. You would have four different IBOutlets (one for each identical button) and each button would a) turn the image 90 degrees, then b) disappear and be replaced with another button. I have not seen any practical implementations of this but it is feasible. Here is a thread on the subject of multiple methods on one button (possibly a better alternative to my idea).

Related

UIView animation stop when UIView willDisappear

I am not much into iOS animation. What I am trying to achieve is a simple message view that slide vertical from bottom of screen to a given y, then after few instants the UIView rollback in vertical to go off screen.
[UIView animateWithDuration:0.5f
animations:^{
self.messageView.frame=CGRectMake(x, y -80, width, height);
}
completion:^(BOOL finished){
if (finished) {
[UIView animateWithDuration:0.5f delay:2.0f options:UIViewAnimationOptionCurveLinear
animations:^{
self.messageView.frame=CGRectMake(x, y + 80, width, height);
}
completion:^(BOOL finished){
// do something...
}
];
}
} ];
This is working fine, but I am having a problem using this mechanism in a iOS UITabBar application: when I change tab, the animation stop, I can infact see that "finished" completion is "false". Therefore the second block is not called, and the message view stays on.
Here are the questions:
my first concern is to understand if the code I have written is correct, regarding the nested animations.
I could solve by ignoring 'finished' and execute code anyway, but I don't feel it is a good idea
within the last completion block, I have put some programming logic, basically I am restoring few UIButtons state, and some other little UI change. At this point I don't know if it is a good idea, it seems not, but how can let the UI knows that the message view has disappeared. NSNotification and KVO seems a bad idea when fast responsive UI change are involved.
You can stop all animations for a layer by sending the layer a removeAllAnimations message.
[sel.view removeAllAnimations];

Can't interact with view out of frame

I have a little UIVIew which is out of the current main view, and I use this code to show it:
[UIView animateWithDuration:0.4
delay:0.0
options: UIViewAnimationOptionTransitionNone
animations:^{
// menuView.center = CGPointMake(menuView.center.x+213, menuView.center.y);
self.view.center = CGPointMake(self.view.center.x+215, self.view.center.y);
}
completion:^(BOOL finished){
}];
And the problem is I can't interact with this view. I have few button on it and they are not clickable... what is the problem?
The Core Animation takes a 'snapshot' of the view and manipulates with a single image, allowing graphic card acceleration. If you want to interact with the view, while it's moving, you'll probably need to make your own animation using a timer and slowly moving the view. It will be CPU-intensive as all the computation will be done by the CPU and not GPU.

XCode/Objective-C: Simultaneous animations for instances of UIView?

I have two IBOutlet variables connected to two instances of UIView in Interface Builder, called blankView and fadedBGView in my ViewController.
How can I set up this code so that the blankView instance will fade into fadedBGView, using the UIViewAnimationOptionTransitionCrossDissolve transition, and the two UIViews can simultaneously transform (move) from their current position (they have equal positions) to 0,0?
What's happening is the fade occurs, and then the fadedBGView view abruptly moves to 0,0.
In other words, I'd like to have the first UIView fade into the second, while simultaneously moving up the screen.
Hopefully this is clear enough to answer.
Best...SL
[UIView transitionFromView:blankView
toView:fadedBGView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {
[blankView removeFromSuperview];
}];
[UIView commitAnimations];
CGRect frame = fadedBGView.frame;
frame.origin.x = 0;
frame.origin.y = 0;
[UIView animateWithDuration:1.0 animations:^{
NSLog(#"UIView Transition/Move Called");
fadedBGView.frame = frame;
}];
iOS 4 and newer provides block-based animations, which your code is already using:
+[UIView animateWithDuration:animations:];
+[UIView animateWithDuration:animations:completion:];
Within the animation block, you can set multiple destination values. See Apple's UIView documentation for a reference to the animatable properties. So within one block, you can modify frames, and alpha (transparency) values of views. I'm not sure how the cross dissolve animation works, but if it's simply one view going from 0 to 1, and another view going from 1 to 0, that's easy to implement.
Instead of
UIViewAnimationOptionTransitionCrossDissolve
use
UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
UIViewAnimationOptionAllowAnimatedContent option allows additional animations during transition. Make sure your fadedBGView has correct starting frame.

UIView animateWithDuration Not Honoring Duration

I have a simple animation that moves a view from one location to another. The animation functions correctly except for the fact that is doesn't follow the duration set in the method declaration...
[UIView beginAnimations:#"listAnimationIn" context:nil];
[UIView animateWithDuration:1.0
delay:1.0
options:UIViewAnimationCurveLinear
animations:^{
lvc.view.frame = CGRectMake(0, 0, 320, 480);
}
completion:nil];
[UIView commitAnimations];
The delay works, but the animation runs FAST no matter what value I put in for duration (I have tried values from 0.5 to 2000). I have also tried a few UIViewAnimationCurve options and nothing seems to work.
Am I missing something?
You don't need the -beginAnimations:context: and the -commitAnimations messages. That's the old way of doing it, and you shouldn't really mix. Just call the -animateWithDuration:delay:options:animations:completion: method. Also, if you add a completion block, it will be passed a boolean variable that will tell you if your animation terminated early or ran to completion. This happens if the animation is too slow, or you have competing animations starting on same view hierarchy (which you do have, with the old style begin/commit calls).

Rotating UIViews become unresponsive

I have a UIViewController subclass that changes its frame when the UI rotates (for example, most commonly, the frame is the same size and centered in both landscape and portrait.) When the view rotates, the view visually changes its frame as expected. But the controls (buttons, scroll views, etc.) that end up in the area of the new frame do not respond to touches. The only controls that respond are the ones that have remained in the original frame (so, if the view moves down and to the left, controls or parts of controls in the upper right corner remain responsive.) Any idea what's going on here?
Here's the code that changes the frame:
- (void) setLandscape:(bool)bLandscape {
if( bLandscape )
[self setFrame:m_landscapeFrame];
else
[self setFrame:m_portraitFrame];
}
And in the bigger view controller that handles rotation directly:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
bool bToLandscape= UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
[UIView beginAnimations:NULL context:nil];
[UIView setAnimationDuration:duration];
[m_pCurrentWindowViewController setLandscape:bToLandscape];
// (Some unrelated stuff happens here...)
[UIView commitAnimations];
}
To me this seems like a bug or at least poor design on Apple's part - there should never be a time when a view is in one position visually and another position in terms of control. But I'm just looking for a way to fix this behavior.
The simplest workaround I found was to update the frame in didRotateFromInterfaceOrientation after animating in willRotateToInterfaceOrientation.