My problem is that I've 2 graphics animation one after the other, but they are done together.
I thought to write a method with completion block, but or I'm doing something wrong, or there is another way to do this.
The animation is a uiview that move out of the screen (closeView) and the default animation of viewcontroller closing.
I want the viewcontroller closes when is over the animation of view.
This is what i've done
- (void)closeViewWithCompletion:(void (^) (BOOL finish))handler {
[self closeView];
handler(YES);
}
-(void) closeView{
[self.myview setFrame:CGRectMake(
-self.myview.frame.size.width
, self.myview.frame.origin.y
, self.myview.frame.size.width
, self.view.frame.size.height
)];
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight];
[animation setDuration:.50];
[animation setDelegate:self];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
CALayer *layer = [self.myview layer];
[layer addAnimation:animation forKey:nil];
[UIView animateWithDuration:0.5 animations:^{
[greyMask setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0]];
} completion:^(BOOL finished) {
[greyMask removeFromSuperview];
}];
}
use:
[vc closeViewWithCompletion:^(BOOL finish) {
[navController popViewControllerAnimated:true];
}
];
call your handler block in completionBlock after your closeView Animation finishes.
- (void)closeViewWithCompletion:(void(^)(BOOL finish))handler {
//closeView Animation
[UIView animateWithDuration:duration delay:0 options: UIViewAnimationOptionCurveEaseOut animations:^{
//code for close view animation
} completion:^(BOOL finished) {
handler(YES) //call your handler in completion block
}];
}
[vc closeViewWithCompletion:^(BOOL finish) {
[self.navigationController popViewControllerAnimated:true];
}];
Related
I'm trying to produce a custom effect when the user presses the default back button (not custom button) of uiviewcontroller's navigation bar. I'm trying to move down a uiview to certain Y position BEFORE popping the view and let the view controller just disappear.
I tried two methods:
Method 1
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[UIView animateWithDuration:0.2 animations:^{
self.cvCell.frame = self.selectedCellFrame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.75
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:self.navigationController.view cache:NO];
} completion:^(BOOL finished) {
[self.navigationController popViewControllerAnimated:NO];
}];
}];
}
Method 2:
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
[UIView animateWithDuration:0.2 animations:^{
self.cvCell.frame = self.selectedCellFrame;
} completion:^(BOOL finished) {
CATransition *transition = [CATransition animation];
[transition setDuration:0.75];
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[transition setType:kCATransitionReveal];
[transition setSubtype:kCATransitionFromLeft];
[transition setDelegate:self];
[self.navigationController.view.layer addAnimation:transition forKey:nil];
}];
}
}
In both the cases the view disappears before the animation on UIView would kick in.
Any suggestions on achieving this?
If you are using Storyboards in your iOS app, you could try to implement a cusom segue animation. You can override the method prepareForSegue:sender: to check if the transaction should occur and the method perform: to bring new view controller on screen. You can then subclass UIStoryboardSegue and enable custom animations in there
iOS Docs
This question already has answers here:
How to animate the change of image in an UIImageView?
(15 answers)
Closed 8 years ago.
i'm trying to animate a UIImageView to change UIImage during the animation, but the duration in the method doesn't work, the animation is done immediately, why?
this is the code:
- (IBAction)do_action:(id)sender {
[UIView animateWithDuration:3.0 animations:^{
[self.my_image setImage:[UIImage imageNamed:#"image1"]];
} completion:^(BOOL finished) {
[self.my_image setImage:[UIImage imageNamed:#"image2"]];
}];
}
i have inserted 3 second for the animation duration, but doesn't work, do it immediately , how i can do?
Try this:
self.my_image.image = [UIImage imageNamed:#"image1"];
CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
[self.my_image.layer addAnimation:transition forKey:nil];
To set the second image, you need to implement a delegate to get notified about the event when the animation completes.
CATransition has a delegate method animationDidStop:finished: which you can use.
Set the delegate property and implement the method:
transition.delegate = self;
...
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
[self.my_image setImage:[UIImage imageNamed:#"image2"]];
}
SetImage is not an animatable Behavior.
Easier way to accomplish is to use setAnimationImages property of UIImageView
//set Your Image names as array
[self.imageView setAnimationImages:[NSArray arrayWithObjects:#"IMG_1_Name",#"IMG_2_Name",nil]];
[self.imageView setAnimationRepeatCount:1];
[self.imageView setAnimationDuration:0.5]; //Your total cycle time. here 0.25 sec for each image
[self.imageView startAnimating];
I have an issue with the following code. When I execute it, There is a undefined delay withing first [CATransaction commit] and CompletionBlock:. No idea what is happening there. This only happen when the app run on the device.
This is the time log,
2013-04-22 15:59:50.893 MyApp[27038:907] ***** A
2013-04-22 **15:59:50.894** MyApp[27038:907] ***** B
2013-04-22 **15:59:53.161** MyApp[27038:907] ***** C
2013-04-22 15:59:53.162 MyApp[27038:907] ***** D
2013-04-22 15:59:53.164 MyApp[27038:907] ***** E
2013-04-22 15:59:53.967 MyApp[27038:907] ***** F
-
NSLog(#"***** A");
[CATransaction begin];
[CATransaction setCompletionBlock:^{
[CATransaction begin];
NSLog(#"***** D");
for (UIView *view in [masterTableView subviews])
{
if (view.tag == 501)
{
[view removeFromSuperview];
break;
}
}
[self.view sendSubviewToBack:masterTableView];
[self.view bringSubviewToFront:detailView];
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setDuration:.8];
[animation setSubtype:transitionFromRight?kCATransitionFromRight:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[CATransaction setCompletionBlock:^{
NSLog(#"***** F");
for (UIView *view in [detailView subviews])
{
if (view.tag == 502)
{
[view removeFromSuperview];
break;
}
}
[self addDetailView];
[self.view sendSubviewToBack:detailView];
[self.view bringSubviewToFront:masterTableView];
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setDuration:.8];
[animation setSubtype:transitionFromRight?kCATransitionFromRight:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[detailView layer] addAnimation:animation forKey:#"transition"];
}];
[[masterTableView layer] addAnimation:animation forKey:#"transition"];
NSLog(#"***** E");
}];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
NSLog(#"***** C");
for (UIView *view in [self.view subviews])
{
if (view.tag == 500)
{
[view removeFromSuperview];
break;
}
}
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionPush];
[animation setDuration:0];
[animation setSubtype:transitionFromRight?kCATransitionFromRight:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[dummyView layer] addAnimation:animation forKey:#"transition"];
}];
[CATransaction commit];
[CATransaction commit];
NSLog(#"***** B");
Have I mistaken some thing ?? Please help.
As I realized CATransaction creates snap shots of the views which I animate. So it gets some time for that task and some delay occur because of that.
So as a solution now I'm animating a UIImageView with the snap shot image of the view. So now the undefined issue was fixed.
I was wondering if it was possible to apply a flashing animation to a UIButton. I have searched but only found the code for a pulse animation which changes the size of my UIButton continuously. I instead was thinking about some kind of flashing animation to alert the user he has to press the button. The only approach to the problem I can think of is by changing the alpha constantly using:
[self setAlpha:0.5];
...but it won't be as visible as a flashing button.
Perhaps not the best way, and doesn't really allow you to stop the flashing... but this is simple, works, and does not hinder user interaction:
- (void)viewDidLoad
{
[self flashOn:myButton];
}
- (void)flashOff:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = .01; //don't animate alpha to 0, otherwise you won't be able to interact with it
} completion:^(BOOL finished) {
[self flashOn:v];
}];
}
- (void)flashOn:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = 1;
} completion:^(BOOL finished) {
[self flashOff:v];
}];
}
Reading all the answers so far I found following solution. It repeats a number of times and does the job for me.
CGFloat oldAlpha = v.alpha;
CGFloat minAlpha = 0.2;
enum UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionCurveEaseInOut;
[UIView animateWithDuration:.3 delay:0.3 options:options animations:^{
[UIView setAnimationRepeatCount:4];
v.alpha = minAlpha;
}
completion:^(BOOL finished) {
v.alpha = oldAlpha;
}];
Try this one:
call this method when you want blink/flash the button
blinkTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(toggleButtonImage:) userInfo:nil repeats:YES];
and write this method
- (void)toggleButtonImage:(NSTimer*)timer
{
if(toggle)
{
[blinkBtn setImage:[UIImage imageNamed:#"ButtonImage.png"] forState: UIControlStateNormal];
}
else
{
[blinkBtn setImage:[UIImage imageNamed:#"ButtonImage1.png"] forState: UIControlStateNormal];
}
toggle = !toggle;
}
in .h write this one
NSTimer *blinkTimer;
BOOL toggle;
and invalidate the timer where you want to stop the flashing/blinking
[blinkTimer invalidate];
Maybe you could have two different .png files [buttons] that cycle back and forth in a loop, assign the same action to them, and have this kick off whenever a certain condition is met. I'd write the code out but it would likely be full of errors. Have you tried something like that?
I did this by creating my own control, subclassing UIControl since Apple doesn't recommend screwing with the view hierarchy of UIButton. I add a background imageView representing the standard background image of the button, and a "glowing" imageView above the background to represent the lit-up state, and toggle its opacity to make it pulse.
I additionally toggle the layer's shadow opacity to make it glow.
Initializing Code:
- (void)TS_commonButtonInit
{
UIImage *shoutoutBackground = [UIImage imageNamed:#"root-navigation-bar-share-button"];
UIImage *shoutoutHighlightedBackground = [UIImage imageNamed:#"root-navigation-bar-share-button-highlighted"];
UIImage *shoutoutPulseImage = [UIImage imageNamed:#"root-navigation-bar-share-button-glowing"];
shoutoutBackground = [shoutoutBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutHighlightedBackground = [shoutoutHighlightedBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutPulseImage = [shoutoutPulseImage stretchableImageWithLeftCapWidth:7 topCapHeight:0];
[[self backgroundView] setImage:shoutoutBackground];
[[self backgroundView] setHighlightedImage:shoutoutHighlightedBackground];
[self setGlowingImage:shoutoutPulseImage];
[self setExclusiveTouch:YES];
[self addSubview:[self backgroundView]];
[self addSubview:[self glowingImageView]];
[[self layer] setShadowColor:[[UIColor colorWithHexString:#"ffc521" alpha:1] CGColor]];
[[self layer] setShadowOpacity:0];
[[self layer] setShadowRadius:5];
[[self layer] setShadowOffset:CGSizeMake(0, 0)];
[[self layer] setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:6] CGPath]];
}
Pulsing Code:
- (void)pulse:(NSInteger)numberOfTimes
{
CGFloat pulseLength = .8;
[[self glowingImageView] setAlpha:0];
CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
[pulseAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[pulseAnimation setDuration:pulseLength];
[pulseAnimation setRepeatCount:numberOfTimes];
[pulseAnimation setAutoreverses:YES];
[pulseAnimation setFromValue:#(0)];
[pulseAnimation setToValue:#(1)];
[pulseAnimation setRemovedOnCompletion:YES];
[[self layer] setShadowOpacity:0];
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:#"shadowOpacity"];
[shadowAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[shadowAnimation setDuration:pulseLength];
[shadowAnimation setRepeatCount:numberOfTimes];
[shadowAnimation setAutoreverses:YES];
[shadowAnimation setFromValue:#(0)];
[shadowAnimation setToValue:#(1)];
[shadowAnimation setRemovedOnCompletion:YES];
[[[self glowingImageView] layer] addAnimation:pulseAnimation forKey:#"opacity"];
[[self layer] addAnimation:shadowAnimation forKey:#"shadowOpacity"];
}
view=[[UIView alloc]init];
[UIView beginAnimations:#"flipping view" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:2];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp
forView:self.view cache:YES];
[self.view addSubview:view.view];
[UIView commitAnimations];
i AM using this but i want animation like two Navigation Controllers.
I am using two UIViews.
You need to apply the transition animation to the parent view that contains the animation of transitioning from one sub view to another.
UIView* view=[[UIView alloc]init];
UIView* parentView = self.view.superview;
[self.view removeFromSuperView];
[parentView addSubview:view];
CATransition *animation = [CATransition animation];
[animation setDelegate:self]; // set your delegate her to know when transition ended
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromRight]; // set direction as you need
[animation setDuration:0.5];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[[parentView layer] addAnimation:animation forKey:#"viewPush"];
You may need to further tweak this code to work in your situation of class design, etc.