screen flash when addsubview by CATransition - objective-c

Many people use this method to add animation on switching views. When I try to add animation effect on adding a subview, the view always flash once。 The reason is that the view add subview immediately at the beginning, after that, the animation starts.
CATransition *transition = [CATransition animation];
transition.duration = 0.35;
transition.removedOnCompletion = NO;
transition.fillMode = kCAFillModeForwards;
transition.type = kCATransitionFade;
transition.subtype = kCATransitionFromBottom;
transition.delegate = self;
[[animationView layer] addAnimation:transition forKey:#"switchView"];
OtherViewController *otherController = [[OtherViewController alloc]init:cityID];
self.myOtherViewController = otherController;
[otherController release];
[self.view insertSubview:myOtherViewController.view atIndex:1];
What's the reasons of problem? How to implement the animation of loading new view without flash?

After modified fillMode to kCAFillModeBoth, it works.
transition.fillMode = kCAFillModeForwards;

Related

custom animation in setCollectionViewLayout:animated: to enlarge the selected cell

I'm changing layouts when selecting a cell in a uicollectionview and have added a custom animation to the collectionview layer
currently I'm using this code:
[self.collectionView performBatchUpdates:^{
CATransition *transition = [CATransition animation];
transition.duration = 0.5f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionMoveIn;
[self.collectionView.layer addAnimation:transition forKey:nil];
[self.collectionView setCollectionViewLayout:self.horizontalPagingLayout animated:NO];
self.galleryInHorizontalScrollMode = YES;
[self.collectionView setPagingEnabled:YES];
} completion:^(BOOL finished) {
[self reloadData];
}];
I would like to change the animation style (transition.type) such that the selected cell will "grow" (or shrink) to the size of the final cell size defined in the collectionview layout
How can this be done?
I've tried solutions as suggested here but they looked very poor

UIActivityIndicatorView keeps animating preceding CATransition pushViewController

I'm trying stop the animation on my UIActivityIndicatorView in the same method that I push a view controller using a CATransition fade.
Instead of stopping the animation, then fading to the next view controller, the UIActivityIndicatorView contiues animating throughout the entire fade, no matter how long I set the duration.
Any ideas how I can get the spinning to stop, then push/fade in the same method?
- (void)pushView:(NSNotification *)notification {
[self.activityIndicator stopAnimating];
NextViewController* nextViewController = [[NextViewController alloc] init];
CATransition *transition = [CATransition animation];
transition.duration = 1.5f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController pushViewController:nextViewController animated:NO];
}
Edit 1
Along the same lines as David's answer, I was able to successfully stopAnimating if I used dispatch_after and delayed for a fraction of a second. Is there a better way to accomplish this?:
- (void)pushView:(NSNotification *)notification {
[self.activityIndicator stopAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.0001 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
NextViewController* nextViewController = [[NextViewController alloc] init];
CATransition *transition = [CATransition animation];
transition.duration = 1.5f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController pushViewController:nextViewController animated:NO];
});
}
I've run into something similar to this before. What you are running is called Synchronous Execution. In synchronous execution, the UI is not updated until the compiler terminates the function, a.k.a. the }. How do you get around this? Simple. Just run any methods to update the UI in an Asynchronous dispatch:
- (void)pushView:(NSNotification *)notification {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
dispatch_async(dispatch_get_main_queue(), ^(void){
[self.activityIndicator stopAnimating];
});
NextViewController* nextViewController = [[NextViewController alloc] init];
CATransition *transition = [CATransition animation];
transition.duration = 1.5f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
[self.navigationController pushViewController:nextViewController animated:NO];
});
}
Whoops! I forgot to put the other code in a plain dispatch! Try the edited code and it should work!
This way the [self.activityIndicator stopAnimating]; is run on a priority thread, while the rest of the code in the function is run in the default priority thread, effectively running the code at the same time, the way you would expect it to.
Cheers!

iOS switch between views of same viewController

I have three views on same viewController and I need to switch beetween them with transitions. Which is the best method to do it? Thank you
Well I am not sure if you have made the question clear .I Guess you want to show the views one at a time.In that case :-
1>You can add the views in a horizontal UIScrollView with its frame size equal to the screen or whatever area you want(width should be equal to width of screen..shown 1 at a time) along with a UIPageControl.
2>The other way is to use the Methods:-
[self.view bringSubViewToFront:yourSubView];
[self.view sendSubViewToBack:yourSubView ];
according to your requirements.
3>You can use Animation to switch between views.
[UIView animateWithDuration:0.7
delay:1.2
options: UIViewAnimationCurveEaseOut
animations:^{
CGRect frame=assignAframeToSwitch;
yourView.frame = frame;
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
OR
_Weak CATransition *transition;
transition = [CATransition animation];
transition.delegate=self;
transition.duration = 0.75;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[[viewcontroller layer] addAnimation:transition forKey:#"transition"];
CATransition is the best way to animate transition
CATransition* trans = [CATransition animation];
[trans setType:kCATransitionPush];
[trans setDuration:0.5];
[trans setSubtype:kCATransitionFromBottom];
// code to change the view//
CALayer *layer = rootViewController.view.layer;
[layer addAnimation:trans forKey:#"Transition"];
Hope it helps.
if you use this bellow code for animation for transitions and then just need to hide and show the view on button click event...
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setType:kCATransitionFromBottom];
[animation setDuration:1.0];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionEaseInEaseOut]];
[[yourViewControllers layer] addAnimation:animation forKey:#"transitionViewAnimation"];
hope,this help you..
:)
The fastest easiest way to do this is with the built in block based UIView transition animations. Just look at the documentation for UIView. Its way simpler than the CATransition methods.

How do I associate pressing a button in my interface to transferring to another view?

I am trying to make it so that when a UIButton in my toolbar that I set in my xib file is pressed, a new controller is loaded into view.
How do I implement that? I have tried duplicating the FlipViewController, but I don't think you can have more than one of these.
iPad (don't use UINavigationController for the whole screen).
You can switch with a nice animation like this:
(works only in app-delegate unless you change the line commented with // works only in app delegate.
UIViewController *ctrl = [[UIViewController alloc] initWithNibName:#"someXIBStuff" bundle:nil];
CAKeyframeAnimation *theAnimation = [CAKeyframeAnimation animation];
theAnimation.values = [NSArray arrayWithObjects:
[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.12,1.12,1)],
[NSValue valueWithCATransform3D:CATransform3DMakeScale(1,1,1)],
nil];
theAnimation.cumulative = YES;
theAnimation.duration = 0.3;
theAnimation.repeatCount = 0;
theAnimation.removedOnCompletion = YES;
theAnimation.timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
nil
];
[self.window.layer addAnimation:theAnimation forKey:#"transform"];
CATransition *transition = [CATransition animation];
transition.duration = 0.3;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
transition.delegate = self;
[self.window.layer addAnimation:transition forKey:nil];
self.window.rootViewController = ctrl; // works only in app delegate
[ctrl release];
iPhone:
Use UINavigationController (if possible). If not, you might use the example above.

iphone sdk MapView update users location

I've successfully put together a mapview with a pin annotation representing the users current position that updates at a set interval. When the location manager updates the user's position, the pin annotation disappears and reappears at the new location. Has anyone played with getting the current user's GPS location to update through the use of an animation, like what is done in Apple's offical mapping application? If so, I'd love some pointers to get this to work. Thanks!
Solution 1:
First, you need to make your view controller implement MKMapViewDelegate if it doesn't already.
Then, implement this method:
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKAnnotationView *aV;
for (aV in views) {
CGRect endFrame = aV.frame;
aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - 230.0, aV.frame.size.width, aV.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.45];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[aV setFrame:endFrame];
[UIView commitAnimations];
}
}
Add your annotations to the MapView and when they are added, this delegate method will be called and will animate the pins from top to bottom as they are added.
The values for timing and positioning can be changed a little bit but I've tweaked it to make it look best/closest to the traditional drop (as far as I've tested).
Solution 2:
Alternatively, if you're making a MKAnnotationView subclass, you can use didMoveToSuperview to trigger the animation. The following does a drop that ends in a slight 'squish' effect
#define kDropCompressAmount 0.1
#implementation MyAnnotationViewSubclass
...
- (void)didMoveToSuperview {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
animation.duration = 0.4;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -400, 0)];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:#"transform"];
animation2.duration = 0.10;
animation2.beginTime = animation.duration;
animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
animation2.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(CATransform3DMakeTranslation(0, self.layer.frame.size.height*kDropCompressAmount, 0), 1.0, 1.0-kDropCompressAmount, 1.0)];
animation2.fillMode = kCAFillModeForwards;
CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:#"transform"];
animation3.duration = 0.15;
animation3.beginTime = animation.duration+animation2.duration;
animation3.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
animation3.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation3.fillMode = kCAFillModeForwards;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:animation, animation2, animation3, nil];
group.duration = animation.duration+animation2.duration+animation3.duration;
group.fillMode = kCAFillModeForwards;
[self.layer addAnimation:group forKey:nil];
}
Hope this helps!
PK