Xcode: Why does my flip animation flip twice? - xcode

I'm having a little problem. I have an UILabel which have an UILongPressGestureRecognicer. When the UILongPressGestureRecognizer is called my app is supposed to switch to a new view using a flip animation.
This is the code I have used for the GestureRecognizer:
UILongPressGestureRecognizer *labelLongPressRecognizer;
labelLongPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(LoadLabelSettings:)];
labelLongPressRecognizer.numberOfTouchesRequired = 1;
labelLongPressRecognizer.minimumPressDuration = 2.0;
[NewLabel addGestureRecognizer:labelLongPressRecognizer];
and this is the code for the view switching animation:
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
[self.view addSubview:LabelSettingsViewController.view];
[UIView commitAnimations];
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight || self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
LabelSettingsViewController.view.frame = CGRectMake(0, 0, 480, 300);
}
My problem is that when I hold down on my UILabel the switch animation begins, but when I release it repeats the animation again. So basically the animation occur twice and I only want it to take place once.
Any ideas?
Thanks in advance :)

Are you checking the sender state, e.g.,
- (void)LoadLabelSettings:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded) // or whatever
// then do the flipping stuff
}
Check out the "Overview" of the "UILongPressGestureRecognizer Class Reference", which talks about the long press being continuous and I presume numerous events could be triggered:
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UILongPressGestureRecognizer_Class/Reference/Reference.html

Related

Make UIImageView Flash - Animation Block

I'm trying to make a UIImageView flash a few times when it collides with another in a small game I'm making.
I found THIS answer on this exchange and the answer that's been accepted as the best is this:
MyImage.alpha = 1.0f;
[UIView animateWithDuration:0.1f //speed of flash
delay:0.0f
options:UIViewAnimationOptionAutoreverse
animations:^ {
[UIView setAnimationRepeatCount:4.0f/2.0f]; //flash few times
MyImage.alpha = 0.0f;
} completion:^(BOOL finished) {
[MyImage removeFromSuperview];
}];
I also like edit 3's code on the 2nd answer down. However the above is the one I've been working with.
It works great but I'm having trouble having my UIImageView returning back to normal, after the flash has happened...
I've tried reseting the alpha value back to 1.0f in the completion block, and even at the end of the method I call to start the animation, but whatever I seem to be trying leaves the image invisible after the flashes... What am I missing? Thank you.
EDIT
I've also tried this way, and the image fades out and comes back, but it will only do it once :( I would like it to do it a few times:
-(void)AnimateComboFlash{ //call when collision occurs
for(int i = 1; i < 5; i++){
[self AltFlash];
}
}
-(void)AltFlash{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5f];
MyImage.alpha = 0.0f;
[UIView commitAnimations];
[self AltFlashBack];
}
-(void)AltFlashBack{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5f];
MyImage.alpha = 1.0f;
[UIView commitAnimations];
}
MyImage.alpha = 1.0f;
[UIView animateWithDuration:0.1f //speed of flash
delay:0.0f
options:UIViewAnimationOptionAutoreverse
animations:^ {
[UIView setAnimationRepeatCount:4.0f/2.0f]; //flash few times
MyImage.alpha = 0.0f;
} completion:^(BOOL finished) {
if (finished) {
[MyImage removeFromSuperview];
}
}];
You need to check if the animation is finished before you set the final value.
So after a long time reading through various questions and answers on this exchange about UIImageView animations, I finally found an answer HERE, by Enceradeira that worked for me, allowing the flash animation to happen, then the image to return to "normal" (with a full 1.0 alpha value).
Using his answer, and the code in my question, this is the method I used to make my UIImageView flash a few times, then return to it's original state:
MyImage.alpha = 1.0f;
[UIView animateWithDuration:0.1f //speed of flash
delay:0.0f
options:UIViewAnimationOptionAutoreverse
animations:^ {
[UIView setAnimationRepeatCount:4.0f/2.0f]; //flash few times
MyImage.alpha = 0.0f;
} completion:^(BOOL finished) {
//[MyImage removeFromSuperview]; //REMOVE THE REMOVE
MyImage.alpha = 1.0f; //RESET ALPHA VALUE AFTER COMPLETION
}];
Hopefully this will help some of you looking for similar answers.

Change pushViewController animation direction

i read alot about faking the animation of pushViewController, but I'm wondering if there is a way to change the actually animation, because I would like to use the navBar and the BackButton of the navigationController.
Currently I'm using this to animate:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:YES];
[views setContentSize:CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height -40)];
CGRect frame = views.frame;
frame.origin.y = - self.view.bounds.size.height;
[UIView beginAnimations:#"viewSlideUp" context:nil];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
views.frame = frame;
[UIView commitAnimations];
}
but I get an overlapping effect, so my view isn't sliding up, the view is sliding away to the top left side.
Has anyone dealed with that problem? Thx for any kinda help!

What is the best way to wait for a loop of UIView animations to finish?

I'm trying to loop over multiple UIViews and perform animation on each, but I'd like to know when all of the animations have finished. What is the best way to call a function when the loop of animations has finished? Alternately, is there a way to wait until all have finished?
I tried using setAnimationDidStopSelector, but it doesn't fire. In this case, I'm clearing some "chips" off a game board by having them fade out then get removed (NumberedChipView is a subclass of UIView). Play cannot continue until the chips are off the board.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop)];
// clear chips
for (HexagonalTile *aTile in tilesToClear) {
NumberedChipView *chipView = [self chipViewForColumn:aTile.column andRow:aTile.row];
[UIView animateWithDuration:0.5 delay:0.3 options:UIViewAnimationCurveLinear animations:^{
chipView.alpha = 0.0;
}
completion:^(BOOL finished){
if (finished) {
[chipView removeFromSuperview];
[self.chipViews removeObject:chipView];
}
}];
}
[UIView commitAnimations];
I also tried CATransaction to no avail:
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[self animationFinished];
}];
// clear chips
for (HexagonalTile *aTile in tilesToClear) {
NumberedChipView *chipView = [self chipViewForColumn:aTile.column andRow:aTile.row];
[UIView animateWithDuration:0.5 delay:0.3 options:UIViewAnimationCurveLinear animations:^{
chipView.alpha = 0.0;
}
completion:^(BOOL finished){
if (finished) {
[chipView removeFromSuperview];
[self.chipViews removeObject:chipView];
//NSLog(#"clearing finished");
}
}];
}
[CATransaction commit];
Update:
I now can get the selector to fire, however it doesn't wait for the loop of animations to finish.
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:)];
Your for loop is firing off all the animations with the same delay and same duration, so they will all start and finish at the same time.
Your completion method is going to be called once for each of your animations.
You could rewrite your code slightly to set a counter to zero before entering the loop, and increment it after each step. When the index is less than the array count, pass a nil completion block. Once the index == the array count, you're on the last item, so pass in a completion block with the code that you want to invoke once the last animation completes.
Note that you can use this index approach to make each animation start at a different time, by increasing the delay amount based on the index value:
delay = .3 + (0.5 * index);
Here's what ended up working for me. I realized that the UIView animateWithDuration methods weren't being associated to the begin/commit section. Rather, the begin/commit sections mark a region of "implicit" animation operations, so I could just set the properties within the animation and it would be implicitly animated.
For example, within the animation below, I simply set the alpha property of the chipView to "0.0" and the chipView (a UIView) is implicitly animated to disappear.
[UIView beginAnimations:#"tilescleared" context:nil];
[UIView setAnimationDelegate: self];
[UIView setAnimationDelay:0.3];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
for (HexagonalTile *aTile in tilesToClear) {
NumberedChipView *chipView = [self chipViewForColumn:aTile.column andRow:aTile.row];
chipView.alpha = 0.0;
}
[UIView commitAnimations];
Then, in my animationDidStop method, I do the "cleanup" and remove and chips from the superview. This animationDidStop method only gets fired when all chipView animations from the loop have finished, which is the tricky thing I was trying to figure out.
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if ([animationID isEqualToString:#"tilescleared"]
&& [finished boolValue]) {
for (HexagonalTile *aTile in self.animationInfo.tilesToClear) {
NumberedChipView *chipView = [self chipViewForColumn:aTile.column andRow:aTile.row];
[chipView removeFromSuperview];
[self.chipViews removeObject:chipView];
}
}
}

xCode ios5: How to fade out a label text after an interval?

I have a little iOS5 app that shows images. I click on the image to show its information. I'd like the information to fade away after a few seconds. Is there a good method to do this?
I can always implement another button action but this would be neater..
Thanks!
Use either NSTimer or performSelector:withObject:afterDelay. Both methods require you to call a separate method that will actually do the fading out which should be fairly straightforward.
Example:
NSTimer
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(fadeOutLabels:) userInfo:nil repeats:NO];
performSelector:withObject:afterDelay:
/* starts the animation after 3 seconds */
[self performSelector:#selector(fadeOutLabels) withObject:nil afterDelay:3.0f];
And you will call the method fadeOutLabels (or whatever you want to call it)
-(void)fadeOutLabels
{
[UIView animateWithDuration:1.0
delay:0.0 /* do not add a delay because we will use performSelector. */
options:UIViewAnimationCurveEaseInOut
animations:^ {
myLabel1.alpha = 0.0;
myLabel2.alpha = 0.0;
}
completion:^(BOOL finished) {
[myLabel1 removeFromSuperview];
[myLabel2 removeFromSuperview];
}];
}
Or you can use the animation block to do all of the work:
-(void)fadeOutLabels
{
[UIView animateWithDuration:1.0
delay:3.0 /* starts the animation after 3 seconds */
options:UIViewAnimationCurveEaseInOut
animations:^ {
myLabel1.alpha = 0.0;
myLabel2.alpha = 0.0;
}
completion:^(BOOL finished) {
[myLabel1 removeFromSuperview];
[myLabel2 removeFromSuperview];
}];
}

animated UIButtons are clickable at destination before they reach destination

I have a UIView that contains a couple UIButtons that I am animating from offscreen to onscreen. I find that the region where they are heading is clickable before they reach it. The animation is pretty simple, so I'm wondering if there is something obvious that I am missing in terms of telling the code to not treat the button as if it is at the final destination (I'm not sure if that is supposed to be the expected behavior and the animation is purely a visual while the clickable region is instantaneously at the destination; I wouldn't expect it to be).
Here is the code I use to animate it. It's basically switching out a sub panel and bringing back a main panel with buttons:
// switch back to main abilities panel
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: kFadeInTime];
CGRect rect = CGRectMake(
480.0f,
mAbilities.mSubPanel.frame.origin.y,
mAbilities.mSubPanel.frame.size.width,
mAbilities.mSubPanel.frame.size.height);
mAbilities.mSubPanel.frame = rect;
[UIView commitAnimations];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: kFadeInTime];
[UIView setAnimationDelay: kFadeInTime];
rect = CGRectMake(
kAbilitiesBorderX,
mAbilities.mPanel.frame.origin.y,
mAbilities.mPanel.frame.size.width,
mAbilities.mPanel.frame.size.height);
mAbilities.mPanel.frame = rect;
[UIView commitAnimations];
As a workaround you can disable user interaction with your panel before animations and reenable it when animation finishes:
// Animation compete handler
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
mAbilities.mSubPanel.userInteractionEnabled = YES;
}
// Animating panel
mAbilities.mSubPanel.userInteractionEnabled = NO;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: kFadeInTime];
[UIView setAnimationDelegate: self];
CGRect rect = CGRectMake(
480.0f,
mAbilities.mSubPanel.frame.origin.y,
mAbilities.mSubPanel.frame.size.width,
mAbilities.mSubPanel.frame.size.height);
mAbilities.mSubPanel.frame = rect;
[UIView commitAnimations];
If you're targeting iOS4 you can (and as specs say should) use block-based animation api:
[UIView animateWithDuration:5.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews
animations:^(void){
CGRect rect = CGRectMake(
480.0f,
mAbilities.mSubPanel.frame.origin.y,
mAbilities.mSubPanel.frame.size.width,
mAbilities.mSubPanel.frame.size.height);
mAbilities.mSubPanel.frame = rect;
}
completion:NULL
];
While animating using blocks user interaction is disabled by default - you can enable it by setting UIViewAnimationOptionAllowUserInteraction flag in options parameter:
... options:UIViewAnimationOptionLayoutSubviews | UIViewAnimationOptionAllowUserInteraction ...

Resources