It's my first post on stackoverflow. I'm a iOS developer newbie and I'm not a native English speaker, so I will do my best to explain my problem.
Problem:
I have added two views to my AppDelegate window and I want to flip from one to the other using:
UIView transitionFromView:toView:
The first view (MainScreenView) has its own ViewController. On the MainScreenView .xib file I have a button with an action that calls the method "goShow" implemented in my AppDelegate. In that method I use UIView transitionFromView:toView: to transition to the second view. So far everything is working fine.
My second view (a scrollview) is declared programmatically in my AppDelegate and has a bunch of pictures inside it (picturesViewController) and on top of those, has a UIPinchGestureRecognizer.
I'm using a gesture recognizer to flip back to my MainScreenView. That is where the problem is. When I do a pinch gesture on the scrollview the MainScreenView.view appears immediately, before the animation, so the flip animation looks wrong.
The code I'm using is:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
mainScreen = [[MainScreenViewController alloc] initWithNibName:#"MainScreenViewController" bundle: [NSBundle mainBundle]];
CGRect frame = self.window.bounds;
int pageCount = 10;
scrollView = [[UIScrollView alloc] initWithFrame:frame];
scrollView.contentSize = CGSizeMake(320*pageCount, 480);
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = FALSE;
scrollView.showsVerticalScrollIndicator = FALSE;
scrollView.delegate = self;
[...] 'While' adding pictures to de scrollView
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
[self.window addSubview: scrollView];
[scrollView setHidden:TRUE];
[self.window addSubview: mainScreen.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void) goShow{
[UIView transitionFromView:mainScreen.view
toView:scrollView
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
-(void) goBackToMain {
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:NULL];
[UIView commitAnimations];
}
I'm using show/hide views instead of addSubview/removeFromSuperView because I tried the add and remove and got an app crash in the pinch gesture, exactly in same step that is failing the animation. Probably it is the same error, but I'm unable to find the reason for this. Any help would be appreciated.
Thanks.
Ok. With Adrian's help, here's the UIPinchGesture code that solved my problem:
[...]
UIPinchGestureRecognizer *twoFingerPinch = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(goBackToMain:)] autorelease];
[scrollView addGestureRecognizer:twoFingerPinch];
-(void)goBackToMain:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded)
{
[UIView transitionFromView:scrollView
toView:mainScreen.view
duration:0.4
options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionShowHideTransitionViews
completion:nil];
[UIView commitAnimations];
}
First, you cannot mix the old method beginAnimation commitAnimation combination with the new block method transitionFromView.
Second, when using block method animation, make sure you use a container (probably a UIView) that will be the parent of the two views you want to switch. Without the container you will be animating the whole view instead. Make sure the container have the same size as the subviews that will switch.
Example:
[container addSubView:frontView];
[container addSubView:backView];
[self.view addSubView:container];
[UIView transitionFromView:backView toView:frontView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
Read more about animations in iOS.
In your example you forgot [UIView beginAnimations].
Related
I have a custom view (which draws callouts/bubbles) that I currently add as a subview to a UIImageView. It works as intended but I would like to animate the operation with a spring-like effect. I am using the below code but it does not work (the block gets executed but without animation):
/* ViewController */
UIImageView *iv = self.imageView;
ZGCBubbleView *bubbleView = [[ZGCBubbleView alloc] init];
bubbleView.hidden = YES;
[iv addSubview:bubbleView];
// UIView animation test
[UIView animateWithDuration:2.0
delay:0
usingSpringWithDamping:0.5
initialSpringVelocity:0.5
options:UIViewAnimationOptionAllowAnimatedContent & UIViewAnimationOptionLayoutSubviews
animations:^{
bubbleView.hidden = NO;
[self.view layoutIfNeeded]; // tried this
}
completion:nil];
I have tried to animate both the hidden property as well as the alpha properties but same result. I have also tried animating the addSubview method, no difference. I started out with a more simple animation as proof of concept but that didn't work either.
The above code is executed within a method which is called during the (void)viewDidAppear:(BOOL)animated cycle. Does this have anything to do with this in that the animation is being executed during the main thread? I have read something to that effect but unsure. Also, I am using auto layout for the UIImageView but didn't think that would matter in this case since the animation is being applied to a custom subview of the UIImageView.
Any help appreciated.
Better use alpha.
UIImageView *iv = self.imageView;
ZGCBubbleView *bubbleView = [[ZGCBubbleView alloc] init];
bubbleView.alpha = 0;
// bubbleView.hidden = YES;
[iv addSubview:bubbleView];
// UIView animation test
[UIView animateWithDuration:2.0
delay:0
usingSpringWithDamping:0.5
initialSpringVelocity:0.5
options:UIViewAnimationOptionAllowAnimatedContent & UIViewAnimationOptionLayoutSubviews
animations:^{
// bubbleView.hidden = NO;
bubbleView.alpha = 1;
//[self.view layoutIfNeeded]; // tried this
}
completion:nil];
Try with this.
UIButton *catchButton = (UIButton *)sender;
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut//UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat |
animations:^{
catchButton.alpha = 0.4;
catchButton.enabled = NO;
}
completion:NULL];
I'm trying to show a fullscreen picture from a smaller one included in a custom UITableViewCell. My code is highly linked to this article
By the way, in this example, the frame : [[UIScreen mainScreen] bounds]is not the good one for me. It's the an UIScrollView's bounds that I've got. I this to add the main screen through a variable inside the cell directly when each cell is created. So I've customized the previous example like this :
//viewDidLoad
self.globalView.frame = [[UIScreen mainScreen] bounds];
//cellForRowAtIndexPath
[cell setFullScreenView:self.globalView];
//fullScreenMethod
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = imageView.frame;
[imageView setFrame:self.fullScreenView.frame];
}completion:^(BOOL finished){
isFullScreen = YES;
}];
return;
}
My problem is that the imageView's new frame is not a full screen but still the UIScrollView's one.
Thank you for your help !
Best approach is create one temporary UIImageView and Show it in full screen,
For animation simply add the temporary UIImageView to location where the image view exists and animate it to full-screen and do revers for normal
Add tap gesture to UIImageView and add this bannerTapped as selector
//This will create a temporary imaget view and animate it to fullscreen
- (void)bannerTapped:(UIGestureRecognizer *)gestureRecognizer {
NSLog(#"%#", [gestureRecognizer view]);
//create new image
temptumb=(UIImageView *)gestureRecognizer.view;
//fullview is gloabal, So we can acess any time to remove it
fullview=[[UIImageView alloc]init];
[fullview setContentMode:UIViewContentModeScaleAspectFit];
[fullview setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bckgrd.png"]]];
fullview.image = [(UIImageView *)gestureRecognizer.view image];
CGRect point=[self.view convertRect:gestureRecognizer.view.bounds fromView:gestureRecognizer.view];
[fullview setFrame:point];
[self.view addSubview:fullview];
[UIView animateWithDuration:0.5
animations:^{
[fullview setFrame:CGRectMake(0,
0,
self.view.bounds.size.width,
self.view.bounds.size.height)];
}];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(fullimagetapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[fullview addGestureRecognizer:singleTap];
[fullview setUserInteractionEnabled:YES];
}
//This will remove the full screen and back to original location.
- (void)fullimagetapped:(UIGestureRecognizer *)gestureRecognizer {
CGRect point=[self.view convertRect:temptumb.bounds fromView:temptumb];
gestureRecognizer.view.backgroundColor=[UIColor clearColor];
[UIView animateWithDuration:0.5
animations:^{
[(UIImageView *)gestureRecognizer.view setFrame:point];
}];
[self performSelector:#selector(animationDone:) withObject:[gestureRecognizer view] afterDelay:0.4];
}
//Remove view after animation of remove
-(void)animationDone:(UIView *)view
{
//view.backgroundColor=[UIColor clearColor];
[fullview removeFromSuperview];
fullview=nil;
}
It can't take a full screen frame because its parent view is the scrollView. Either show view modally or somehow move imageView directly under view controller's main view.
I am a bit new to iOS development. I am working on an app that has about 5,000 visual data points, organized in categories. I want to present them in a UICollectionView with very tiny UICollectionViewCells. When a user taps on something in a category, the category zooms in with the selected cell in focus. Pretty much like how the "Photos" tab of the iOS 7 Photos app works: Years > Collections > Moments.
How do I go about implementing a custom transition like that? Are there any open-source libraries already written for accomplishing this?
If you can't find any library, try to play with this code I wrote for custom animations. You can specify a start point, an end point, start scale and end scale of a view that you want to zoom and scale in or out. See below an example how I use it. The point is to use a fake view to push it with animation, then push and pop your real view without animation. viewobj is set to fade in from alpha 0 to alpha 1, zoomableView will scale from the point/scale you give as parameter to the final position you set it in your storyboard/xib. Hope it will help.
# you can create a category vor UIView and add these methods
- (void) addSubView:(UIView*)viewObj animateFromPoint:(CGPoint)point zoomableView:(UIView*)view minScale:(CGSize)scale completion:(void (^)(void))completionBlock{
CGPoint center = view.center;
[view setTransform:CGAffineTransformMakeScale(scale.width, scale.height)];
viewObj.alpha = 0;
view.center = point;
[self addSubview:viewObj];
[self addSubview:view];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
view.center = center;
[view setTransform:CGAffineTransformMakeScale(1.0, 1.0)];
viewObj.alpha = 1;
}
completion:^(BOOL fin){
if(completionBlock)
completionBlock();
}];
}
- (void) removeFromSuperviewAnimateToPoint:(CGPoint)point zoomableView:(UIView*)view minScale:(CGSize)scale completion:(void (^)(void))completionBlock{
CGRect startFrame = view.frame;
self.alpha = 1;
[self.superview addSubview:view];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
view.center = point;
[view setTransform:CGAffineTransformMakeScale(scale.width, scale.height)];
self.alpha = 0;
}
completion:^(BOOL fin){
[self removeFromSuperview];
[view removeFromSuperview];
[view setTransform:CGAffineTransformMakeScale(1, 1)];
view.frame = startFrame;
[self addSubview:view];
if(completionBlock)
completionBlock();
}];
}
And to use them:
# your did select item at index path:
self.itemDetails = [self.storyboard instantiateViewControllerWithIdentifier:#"ItemDetailsVC"];
ItemDetailsVC* itd = [self.storyboard instantiateViewControllerWithIdentifier:#"ItemDetailsVC"];
__weak UIViewController* wself = self;
[self.view addSubView:self.itemDetails.view animateFromPoint:self.zoomedFrom zoomableView:self.itemDetails.viewZoomable minScale:CGSizeMake(0.371134, 0.371134) completion:^{
[wself.navigationController pushViewController:itd animated:NO];
}];
self.addSubviewIsUp = YES;
# back button of the view you added:
[self.navigationController popViewControllerAnimated:NO];
# viewdidapear of your main screen
if(self.addSubviewIsUp){
[self.addVc.view removeFromSuperviewAnimateToPoint:CGPointMake(160, 75) zoomableView:self.addVc.zoomableView minScale:CGSizeMake(0.01, 0.01) completion:^{
}];
}
self.addSubviewIsUp = NO;
I am attempting a simple UIView animation in the viewDidLoad or viewDidAppear method but it doesn't animate.
UIImage *bluredScreenshot = [self.parentViewControllerScreenshot applyBlur];
[UIView transitionWithView:self.screenshotView duration:3.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
self.screenshotView.image = bluredScreenshot;
} completion:nil];
Simple cross dissolving two images. When ran from viewDidLoad or viewDidAppear the image changes but isn't animated.
But lets say I run the animation from a method after I press a button, it will animate. Why? Seem strange.
Is it possible to make it from the viewDidLoad method? How would you solve this?
Thanks.
You need to fade in the screenshot. If you're using two images, you'll need to place one image view atop the other.
pop this inside viewDidAppear: after calling [super viewDidAppear:animated];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.screenshotView.frame];
[self.view addSubview:imageView];
[imageView setAlpha:0.0f];
imageView = blurredScreenshot;
[UIView animateWithDuration:0.3f animations:^{
[imageView setAlpha:1.0f];
} completion:^(BOOL finished){
self.imageView.image = blurredScreenshot;
[imageView removeFromSuperview];
}];
when the view is loading you can't animate because there isn't anything to animate. Try in viewdidapear: and Don't use transition
[UIView animateWithDuration:3.
delay:0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.screenshotView.image = bluredScreenshot;
}
completion:nil];
Just a reminder, sometimes your problem can be caused by not calling:
self.layoutIfNeeded()
I'm new iphone developer i have problem uiview animation for ipad landscape mode.i have two view view1(like a split view) and view2(covered remaining window).when i touch move right to left view2 it will be overriding the view1 with moving animation.at same time when i touch move left to right view2 come and fit the old position.please share your ideas
With Regards,
Rajesh.
Hi all i found the answer finally,
- (void)viewDidLoad
{
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(rightSwipeHandle:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[recognizer setNumberOfTouchesRequired:1];
[secondView addGestureRecognizer:recognizer];
[recognizer release];
UISwipeGestureRecognizer *recognizerleft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(leftSwipeHandle:)];
[recognizerleft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[recognizerleft setNumberOfTouchesRequired:1];
[secondView addGestureRecognizer:recognizerleft];
[recognizerleft release];
[self.view addSubview:secondView];
[super viewDidLoad];
}
//To set the frame position of the view
- (void)rightSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"rightSwipeHandle");
[UIView beginAnimations:#"viewanimations" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationDelegate:self];
secondView.frame=CGRectMake(360, 0, 660, 768);
[UIView commitAnimations];
}
//To set the frame position of the view
- (void)leftSwipeHandle:(UISwipeGestureRecognizer*)gestureRecognizer
{
NSLog(#"leftSwipeHandle");
[UIView beginAnimations:#"viewanimations" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationDelegate:self];
secondView.frame=CGRectMake(200, 0, 858, 768);
[UIView commitAnimations];
}
if i understand correctly, you want a sliding animation between 2 views. if so:
Make a ViewController that will hold these two views. inside this view controller's .m file define a transition method that contains the following and gets called by your buttons/other action triggers:
CGFloat windowWidth = self.mainView.frame.size.width;
CGFloat windowHeight = self.mainView.frame.size.height;
CGRect offScreenLeft = CGRectMake(-1*windowWidth, 0.0, windowWidth, windowHeight);
CGRect onScreen = self.mainView.frame;
CGRect offScreenRight = CGRectMake(windowWidth, 0.0, windowWidth, windowHeight);
if (direction == rightToLeft)
{
rightView.frame = offScreenRight;
[self.view addSubview:rightView];
[UIView animateWithDuration:0.65
animations:^{
leftView.frame = offScreenLeft;
rightView.frame = onScreen;
}
completion:^(BOOL finished){
[leftView removeFromSuperview];
}];
}else if (direction == leftToRight){
self.leftViewController.view.frame = offScreenLeft;
[UIView animateWithDuration:0.65
animations:^{
rightView.frame = offScreenRight;
leftView.frame = onScreen;
}
completion:^(BOOL finished){
[rightView removeFromSuperview];
}];
}
}
In general, make sure you are adding your subview to the view currently on screen, and make sure you set the appropriate bounds. Check that your view is not nil:
if(myView){
// not nil. thats good
}else {
// nil. this is bad. make sure myView is being initialized properly (if at all)
}
Finally, make sure neither the opacity nor the alpha property on your subview is set to 0 (you'll want these at 1 if you want it to show up completely and between 0 and 1 for a transparency effect).