UIView beginAnimations fails on selector - objective-c

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelay:4];
[UIView setAnimationDuration:5];
navigation.frame = CGRectOffset(navigation.frame, 0, 430);
[UIView commitAnimations];
Code block above works fine when called manually on viewDidLoad function or with button tap. But when i try to call that block within a selector function like below, animation doesnt effect. Object jumps to position. What would cause to that?
if ([delegate respondsToSelector:#selector(carouselDidEndScrollingAnimation:)])
{
[delegate carouselDidEndScrollingAnimation:self];
}
- (void) carouselDidEndScrollingAnimation:(iCarousel *)carousel{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:5];
navigation.frame = CGRectOffset(navigation.frame, 0, 430);
[UIView commitAnimations];
}
icarousel github

Still don't know the real problem but
[self performSelector:#selector(makeAnim) withObject:nil afterDelay:0.0001];
solved my problem.
Hope helps anyone.
Still needs a better solution.

Related

How can I add a Hide ad button?

I am trying to add a button so the user hide the add, I did this in swift but it seems quite different using objective-c this is the code I am using to display an add
#pragma mark iAd Deligate Methods
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];
}
-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];
}
I tried using
- (IBAction)hideAd:(id)sender {
[ADBannerView.hidden = YES];
}
But this doesn't work, any ideas? thanks!
ADBannerView is the class. It doesn't have a hidden attribute for you to set to hide all ads. Instead, grab your banner and do this instead:
banner.hidden = YES;
That is, you need a reference to your banner, as opposed to it being passed in in the other two methods. You should keep a reference to the ad when you created it.
The problem is in your hideAd:(id)sender method.
- (IBAction)hideAd:(id)sender {
[ADBannerView.hidden = YES];
}
ADBannerView is the class of your banner, not the banner itself.
The code below should work fine.
Please note: _banner should be replaced with the property name in which you declared your ADBannerView.
- (IBAction)hideAd:(id)sender {
[_banner setHidden: YES];
}

How to replace button with an animation in Xcode

I have a UIButton in my code that moves steadily across the screen. Currently, when the user presses the button, the alpha changes to 0 and it just disappears. What I'd like to do is run a separate animation after the button is pressed/it has disappeared. Seems easy enough but the catch is I need to run the animation at the exact point of the button when it is pressed. And I'm drawing a blank on how to make this happen. Any help will be much appreciated! I'll post some relevant code below.
-(void)movingbuttons{
movingButton2.center = CGPointMake(x, y);
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(moveObject)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
-(void)moveObject{
movingButton2.center = CGPointMake(movingButton2.center.x , movingButton2.center.y +1);
}
-(IBAction)button2:(id)sender {
[UIView beginAnimations:nil context:NULL];
[movingButton2 setAlpha:0];
[UIView commitAnimations];
}
Replace your button2 action with below code and implement the someOtherMethodWithAnimation method with the animation you want :)
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
movingButton2.alpha = 0;
[UIView commitAnimations];
[self performSelector:#selector(someOtherMethodWithAnimation) withObject:nil afterDelay:1.0];
Replace your animation with:
[UIView animateWithDuration:0.25
animations:^{
self.movingbutton2.alpha = 0.0;
// modify other animatable view properties here, ex:
self.someOtherView.alpha = 1.0;
}
completion:nil];
Just a nit picking point, but is the button in your view controller's .xib file correctly hooked up to your IBOutlets and IBActions?
UPDATE:
You are not limited to modifying that one button in your method. You add what ever code you want in the animation block (see the udated axample above).
UIView animatable properties, there is an animation section there.
Another approach could be (I am just using alpha as an example):
[UIView animateWithDuration:1.0
animations:^{
self.movingButton2.alpha = 0.0;
}
completion:^{
[UIView animatateWithDuration:0.25
animations:^{
self.someOtherView.alpha = 1.0;
}
completion:nil];
}];
This will more likely guarantee the animations will hapen one after another.

Multiple UIView Animations

I am trying to perform multiple UIView animations one after the other. However, I've heard that it's bad practice to perform multiple UIView animations one after the other, and that I should instead use Core Animation. I tried this code:
//First Animation
[UIView beginAnimations:#"animation1" context:nil];
[UIView setAnimationDuration:2];
nwView.backgroundColor = [UIColor redColor];
nwView.frame = CGRectMake(CGRectGetMidX(screenSize),
CGRectGetMinY(screenSize),
width,
height);
nwView.transform = CGAffineTransformMakeRotation(45.0f);
[UIView commitAnimations];
//Second Animation
[UIView beginAnimations:#"second animation" context:nil];
[UIView setAnimationDuration:2];
nwView.transform = CGAffineTransformMakeScale(0.5, 0.33);
nwView.backgroundColor = [UIColor purpleColor];
[UIView commitAnimations];
But it only does the second animation. I know this question is similar to UIView two animations coexisting, but it has a slightly different context.
I don't think there is anything wrong with doing 2 animations in a row using UIView blocks. Just make sure you start your second animation in the completino block of the first animation.
Without blocks (your example) it is not working as you will have to set a delegate to the animation or set a selector for setAnimationDidStopSelector. There you should start the second animation.
But again, nothing wrong in doing animations with blocks (it is the preferred way).
If you are looking to do multiple animations right after another this is not the way to do it. The code you posted with execute at almost the same time, meaning the animations would be performed at about the same time.
Instead what you should do is set the delegate for the first animation, and then do the first animation. Then when the animationDidStop method is called for the first animation, you should do the second animation. This makes sure they are one after another.
This is how you would do it, assuming you call doMyAnimations to start the animation.
-(void)doMyAnimations{
//First Animation
[UIView beginAnimations:#"animation1" context:nil];
[UIView setAnimationDuration:2];
[UIView setAnimationDelegate:self];
nwView.backgroundColor = [UIColor redColor];
nwView.frame = CGRectMake(CGRectGetMidX(screenSize),
CGRectGetMinY(screenSize),
width,
height);
nwView.transform = CGAffineTransformMakeRotation(45.0f);
[UIView commitAnimations];
}
- (void)animationWillStart:(NSString *)animationID context:(void *)context{
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
if([animationID isEqualToString:#"animation1"]){
//Second Animation
[UIView beginAnimations:#"second animation" context:nil];
[UIView setAnimationDuration:2];
nwView.transform = CGAffineTransformMakeScale(0.5, 0.33);
nwView.backgroundColor = [UIColor purpleColor];
[UIView commitAnimations];
}
}
Keep in mind that the nwView would have to be accessible throughout the entire class. If it isn't you can either make it an instance variable, or find another way to get access to it in the animationDidStop method.
You can use blocks for this purpose and get a very clean result.
NSMutableArray* animationBlocks = [NSMutableArray new];
typedef void(^animationBlock)(BOOL);
// getNextAnimation
// removes the first block in the queue and returns it
animationBlock (^getNextAnimation)() = ^{
animationBlock block = (animationBlock)[animationBlocks firstObject];
if (block){
[animationBlocks removeObjectAtIndex:0];
return block;
}else{
return ^(BOOL finished){};
}
};
//add a block to our queue
[animationBlocks addObject:^(BOOL finished){;
[UIView animateWithDuration:1.0 animations:^{
//...animation code...
} completion: getNextAnimation()];
}];
//add a block to our queue
[animationBlocks addObject:^(BOOL finished){;
[UIView animateWithDuration:1.0 animations:^{
//...animation code...
} completion: getNextAnimation()];
}];
//add a block to our queue
[animationBlocks addObject:^(BOOL finished){;
NSLog(#"Multi-step Animation Complete!");
}];
// execute the first block in the queue
getNextAnimation()(YES);
Taken from: http://xibxor.com/objective-c/uiview-animation-without-nested-hell/

How to stop executing FOR loop until code is completed

I made this thing. It has no purpose other than for demonstration to myself. Essentially, I'm moving a view that I created around the screen in a loop. The problem is that it doesn't wait until it's done with one animation before starting the other, and so the view bypasses the first two and ends up at the last toastRect after the for loop is done, and it doesn't keep moving after that. How can I force the code to complete each animation before moving on to the next?
int i;
for (i=0; i < 100; i++) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:9];
toast.view.frame = toastRect1;
[UIView commitAnimations];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:9];
toast.view.frame = toastRect2;
[UIView commitAnimations];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:9];
toast.view.frame = toastRect;
[UIView commitAnimations];
NSLog(#"%d",i);
}
}
I think you need to use + (void)setAnimationDidStopSelector:(SEL)selector. Take a closer look at http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html if you want.
You can use the setAnimationDidStopSelector method to chain the animations. Check the docs for details: http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html%23//apple_ref/occ/clm/UIView/setAnimationDidStopSelector:

How to let two animations for UIView executed one by one

I have a small UIView and want to let it move to center of screen first, and then, zoom to full screen.
But when I begin start an animation like
[UIView beginAnimations:#"animation1" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(showDetailToFullscreen)];
self.currentDetailVC.frame = centerFrame;
[UIView commitAnimations];
And in the same controller, I have a method:showDetailToFullscreen
- (void)showDetailToFullscreen {
CGRect screenFrame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[UIView beginAnimations:#"animation2" context:nil];
[UIView setAnimationDuration:0.5];
self.currentDetailVC.view.frame = screenFrame;
[UIView commitAnimations];
}
but when start, it still executed together.
I think the problem they are still in the same transaction. But how can I let these two animation executed one by one? Appreciate for any answer!
Try this instead of the setAnimationDidStopSelector:
[self performSelector:#selector(showDetailToFullscreen) withObject:nil afterDelay:0.5];
It's now considered much better to annimate views using the 'blocks' methods that can be found in the "Animating Views with Blocks" section in the UIView Class Reference.
In most of these methods you can specify a "completion" block of code that can be used to start off a second animation when the first animation completes. You could also call showDetailToFullscreen within this completion block.
I'd reccommend trying this method instead.
Are you targetting iOS 4 or later? If so, I recommend using the block-based animation methods instead. What you want to do is very easy:
Example from UIView docs:
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];