Animating UIViews to get crossfade effect not working very well - iphone

I have successfully created a icon menu that displays from a tabBar selection. You can view this menu in either Portrait or Landscape.
because of the space on the screen I have made it so that in portrait you can view 4x4 icons.. however due to sizing when viewed in landscape this dose not work that well.. so I have made it so that you can view 2 rows of 6 and 1 row of 4. because of this, I have decided to create two UIViews for the menu, when the device rotates I switch between the two views.
i.e. if Portrait current and device is rotated load Landscape and unload Portrait and vice versa.
This is the code I am using to change views on the device rotation, this works perfectly fine (might not be the best code but its the best I could do)
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait)
{
if([jumpBarContainerLandscape superview])
{
// Device is changing from landscape to protrait change views to fit
// load landscape view
jumpBarContainerPortrait = [[UIView alloc] initWithFrame:CGRectMake(0.0, (367 - jumpBarHeightPortrait), 320.0, (jumpBarHeightPortrait + 49.0))];
jumpBarContainerPortrait.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
jumpBarContainerPortrait.alpha = 0.0;
// add jumpbar container to view
[self.view insertSubview:jumpBarContainerPortrait belowSubview:actionTabBar];
[UIView animateWithDuration:0.2
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerLandscape.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
}
}];
[UIView animateWithDuration:0.2
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerPortrait.alpha = 1.0;
} completion:^(BOOL finished) {
if (finished) {
// remove subView for superView
[jumpBarContainerLandscape removeFromSuperview];
}
}];
}
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
if ([jumpBarContainerPortrait superview])
{
// Device is changing from portrait to landscape change views to fit
// load landscape view
jumpBarContainerLandscape = [[UIView alloc] initWithFrame:CGRectMake(0.0, (207 - jumpBarHeightLandscape), 480.0, (jumpBarHeightLandscape + 49.0))];
jumpBarContainerLandscape.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
jumpBarContainerLandscape.alpha = 0.0;
// add jumpbar container to view
[self.view insertSubview:jumpBarContainerLandscape belowSubview:actionTabBar];
// fade out
[UIView animateWithDuration:0.2
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerPortrait.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
}
}];
// fade in
[UIView animateWithDuration:0.2
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerLandscape.alpha = 1.0;
} completion:^(BOOL finished) {
if (finished) {
// remove subView for superView
[jumpBarContainerPortrait removeFromSuperview];
}
}];
}
}
Now the issue I am having is that the animation between the two UIViews is quite ugly, its not very smooth you can see the two different views on the animation etc which is undesirable.. I was wondering if anyone could think of a nice way to crossfade between the two making it look abit smoother etc...
any help would be greatly appreciated.
EDIT:
So I have just tried to create a CATransaction, however I have an error on one line giving me this error No visible #interface for 'UIView' declares the selector 'jumpBarContainerPortrait' I have added a comment to the line where I get this error below.. any help would be appreciated
[CATransaction begin];
CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 3.50;
[self.view insertSubview:jumpBarContainerPortrait belowSubview:actionTabBar];
[[self.view jumpBarContainerPortrait] addAnimation:animation forKey:#"Fade"]; // Error is happening here!
[CATransaction commit];

Instead of your separate fade in and fade out animations, use the UIView method "transitionFromView". Here's an example:
[UIView transitionFromView:jumpBarContainerLandscape
toView:jumpBarContainerPortrait
duration:crossDissolveTime
options:UIViewAnimationOptionTransitionCrossDissolve
completion:NULL];

Related

Custom UIView doesn't get removed from superview when loaded again while animating

The question explains it all actually.
I load a custom UIView on top of my current view, animated, using this code:
- (void)showView
{
self.blurView.alpha = 0.f;
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
self.blurView.alpha = 1.f;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
self.blurView.alpha = 0.f;
} completion:nil];
}];
}
It works, but when I perform -(void)showView again while it is still animating, the custom view doesn't get removed from the screen.
It just stays like this:
I figured out what the problem was.
blurView is a public variable and every time I did -(void)showView it used the same variable, setting the alpha to 0.f just once, thus never changing the alpha of the first show.
I declared the variable blurView in the method itself and now it works because every blurView gets it's own pointer.
-(void)someMethod
{
//Create a live blur view
FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
blurView.center = CGPointMake(self.view.window.frame.size.width / 2, self.view.window.frame.size.height / 2);
blurView.layer.cornerRadius = 20.f;
[self.view.window addSubview:blurView];
[self showView:(blurView)];
}
- (void)showView:(FXBlurView *)blurView
{
//Make full transparent before showing
blurView.alpha = 0.f;
//Start animation
[FXBlurView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
blurView.alpha = 1.f;
} completion:^(BOOL finished) {
if (finished)
{
//End animation
[FXBlurView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
blurView.alpha = 0.f;
} completion:nil];
}
}];
}
You should add to the top of your function this line:
[self.view.layer removeAllAnimations];
It will remove all of the active animations.
It doesn't work because you have implemented a delay, use animation block with delay - it will create animation keys that could be removed with this function above.
[UIView animateWithDuration:0.3 delay:0.0
options:UIViewAnimationOptionAllowUserInteraction
animations:^
{
// ...
} completion:NULL];

iPhone slide animation when view is loaded

How to perform a sliding animation when a view is being loaded in an iPhone application?
I have a ViewController in which I have subview. I want that the subview be loaded with an animation, sliding from the left to the right.
I got this code so far:
-(void) showAnimation{
[self.view addSubview:geopointView]
geopointView.frame = CGRectMake(20,150,550,200)// somewhere offscreen, in the direction you want it to appear from
[UIView animateWithDuration:10.0
animations:^{
geopointView.frame = CGRectMake(20,150,550,200)// its final location
}];
}
why not?
-(void) showAnimation{
[self.view addSubview:geopointView]
geopointView.frame = CGRectMake(-200,150,550,200)// just set a different frame
[UIView animateWithDuration:10.0
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^{
geopointView.frame = CGRectMake(20,150,550,200)// its final location
}
completion:nil];
}

Programatic UIViews being rotated correctly

I have been doing pretty much all of my User Interface programmatically with slight alterations being performed in Interface Builder.. but 99% of all the UI is exclusively done in code, because I feel there is a certain amount of flexibility gained by doing it this way.
However I am now having issues dealing with the rotation of the device, as I have several UIViews being added as subviews I am faced with a rotational problem as this is how I declare the views generally
htmlTest.webViewTest.frame = CGRectMake(4.0, 4.0, 312.0, 363.0);
and because of this fixed CGRectMake when the device is rotated the view stays the same size and dosent fit the orientation of the view properly.
So I have worked on a solution which is in my opinion horrible.. There are a couple of views that I animate in and users can select options from them then I animate them out.. but they need to be able to handle loading in either portrait or landscape and then if while they are loaded they need to be able to handle a rotation from either orientation to the other.
This is how I have done one of the views.
#pragma createAwesomeJumpBar
- (void)jumpBarButtonPosition:(int)changeView
{
// ChangeView is used to check if the this method is being called from a device rotation or from a button press (0, being rotation and 1, being tabbarButton touch
// if tabbar selected
if (changeView == 1) {
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait)
{
if (![jumpBarContainerPortrait superview]) {
// load portrait view
jumpBarContainerPortrait = [[UIView alloc] initWithFrame:CGRectMake(0.0, 480.0, 320, (jumpBarHeightPortrait + 49.0))];
jumpBarContainerPortrait.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
// add jumpbar container to view
[self.view insertSubview:jumpBarContainerPortrait belowSubview:actionTabBar];
[UIView animateWithDuration:0.6
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerPortrait.frame = CGRectMake(0.0, (367 - jumpBarHeightPortrait), 320.0, (jumpBarHeightPortrait + 49.0)); // display jumpBar
} completion:^(BOOL finished) {
if (finished) {
NSLog(#"YAY!");
}
}];
}
else if ([jumpBarContainerPortrait superview]) {
//unload portrait view
[UIView animateWithDuration:0.6
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerPortrait.frame = CGRectMake(0.0, 480.0, 320.0, (jumpBarHeightPortrait + 49.0)); // display jumpBar
// remove selected tabButton highlight
[actionTabBar setSelectedItem:nil];
} completion:^(BOOL finished) {
if (finished) {
// remove subView for superView
[jumpBarContainerPortrait removeFromSuperview];
}
}];
}
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
if (![jumpBarContainerLandscape superview]) {
// load landscape view
jumpBarContainerLandscape = [[UIView alloc] initWithFrame:CGRectMake(0.0, 320, 480.0, (jumpBarHeightLandscape + 49.0))];
jumpBarContainerLandscape.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
// add jumpbar container to view
[self.view insertSubview:jumpBarContainerLandscape belowSubview:actionTabBar];
[UIView animateWithDuration:0.6
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerLandscape.frame = CGRectMake(0.0, (207 - jumpBarHeightLandscape), 480.0, (jumpBarHeightLandscape + 49.0)); // display jumpBar
} completion:^(BOOL finished) {
if (finished) {
NSLog(#"YAY!");
}
}];
}
else if ([jumpBarContainerLandscape superview]) {
// remove landscape view
[UIView animateWithDuration:0.6
delay:0.0f
options:UIViewAnimationCurveEaseIn
animations:^{
jumpBarContainerLandscape.frame = CGRectMake(0.0, 320, 480.0, (jumpBarHeightLandscape + 49.0)); // display jumpBar
[actionTabBar setSelectedItem:nil];
} completion:^(BOOL finished) {
if (finished) {
// remove subView for superView
[jumpBarContainerLandscape removeFromSuperview];
}
}];
}
}
}
// if device rotated selected
else if (changeView == 0) {
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait)
{
if([jumpBarContainerLandscape superview])
{
// Device is changing from landscape to protrait change views to fit
// load landscape view
jumpBarContainerPortrait = [[UIView alloc] initWithFrame:CGRectMake(0.0, (367 - jumpBarHeightPortrait), 320.0, (jumpBarHeightPortrait + 49.0))];
jumpBarContainerPortrait.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
jumpBarContainerPortrait.alpha = 1.0;
// add jumpbar container to view
[UIView transitionFromView:jumpBarContainerLandscape
toView:jumpBarContainerPortrait
duration:animationSpeed
options:UIViewAnimationOptionTransitionCrossDissolve
completion:NULL];
[self.view insertSubview:jumpBarContainerPortrait belowSubview:actionTabBar];
}
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)
{
if ([jumpBarContainerPortrait superview])
{
// Device is changing from portrait to landscape change views to fit
// load landscape view
jumpBarContainerLandscape = [[UIView alloc] initWithFrame:CGRectMake(0.0, (207 - jumpBarHeightLandscape), 480.0, (jumpBarHeightLandscape + 49.0))];
jumpBarContainerLandscape.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
jumpBarContainerLandscape.alpha = 1.0;
// add jumpbar container to view
[UIView transitionFromView:jumpBarContainerPortrait
toView:jumpBarContainerLandscape
duration:animationSpeed
options:UIViewAnimationOptionTransitionCrossDissolve
completion:NULL];
[self.view insertSubview:jumpBarContainerLandscape belowSubview:actionTabBar];
}
}
}
}
in this example, I have two views landscape and portrait, obviously as the names go each are for their respective orientations.. the logic above goes along the lines of this
if tabbarselected
if !view visible
if device orientation portrait
animate in portrait view.
if device orientation landscape
animate in landscape view
if view visible
if device orientation portrait
animate out portrait view
clear tabbar
if device orientation landscape
animate out landscape view
clear tabbar
if !tabbarselected //meaning listener has identified orientation of device has changed
if device orientation portrait
unload portrait
load landscape
if device orientation landscape
unload landscape
load portrait
I would like to know if there is an easier way than going through all of this hassle! I am still fairly inexperienced so this was my best attempt.. I am hoping someone out there knows of an easier approach than having to do all of this leg work to get views being added to other views as subviews adjusting for orientation properly
any help would be greatly appreciated! I'm desperate lol :)
See the autoresizingMask documentation. Gives you all the same springs and struts control that you have in Interface Builder. E.g.:
CGRect frame = CGRectMake(margin, margin, self.view.frame.size.width - margin * 2, self.view.frame.size.height - margin * 2);
UIView *mySubview = [[UIView alloc] initWithFrame:frame];
[self.view mySubview];
mySubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Also, if you decide that autoresizingMask is not enough (for example, when you're moving objects with respect to each other to really fine tune the portrait versus landscape orientation), I'd suggest you do this layout process in viewWillLayoutSubviews for iOS5, (or willAnimateRotationToInterfaceOrientation in iOS4 or earlier). This way you don't need to animate the change yourself and the animation will be done in conjunction with the rest of the screen rotation animation.

iPhone UIAnimation using blocks not working

As suggested by this popular answer, I am using blocks for animating views as per the code:
UIView *whiteout = [[UIView alloc] initWithFrame:self.view.frame];
whiteout.backgroundColor = [UIColor blackColor];
[self.view addSubview:whiteout];
[UIView transitionWithView:self.view duration:2.0 options:UIViewAnimationTransitionFlipFromRight animations:^{ [whiteout removeFromSuperview]; } completion:nil];
However the animation does not happen and the whiteout view is removed immediately. What am i missing here??
Removing from a superview is not animatable. If you want to fade out your view, try setting its alpha to 0, then remove it on completion:
[UIView transitionWithView:self.view duration:2.0 options:UIViewAnimationTransitionFlipFromRight animations:^{
whiteout.alpha = 0.0;
} completion:^(BOOL completion){
[whiteout removeFromSuperview];
}];

Creating a faded out screen effect iphone

I have a view controller....when the user presses a button I want a black screen to fade in over the top and a uiactivityindicator to appear on top of the faded screen.
How can I get this animated fade in effect?
-(IBAction) loginToApp:(id)sender{
//fade in view
}
Add another view over the top of your view, colored solid black. You can do it in IB or programatically, just make sure it has a higher z-order (is on top). Make its alpha = 0. Then:
-(IBAction) loginToApp:(id)sender{
[UIView animateWithDuration:1.5 animations:^{ myview.alpha = 1.0; }]
}
...obviously you need an outlet or variable myview connected to that view. 1.5 = seconds. Change for your needs.
Sure you can. You can create the overlay view however you wish, but this will work (assuming you create appropriate instance variables somewhere). My code was in my view controller, so [self view] returns the view I want to shade over.
shadeView = [[UIView alloc] initWithFrame:[[self view] bounds]];
shadeView.backgroundColor = [UIColor blackColor];
shadeView.alpha = 0.0f;
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorStyleWhiteLarge];
spinner.center = CGPointMake(CGRectGetMidX([shadeView bounds]),
CGRectGetMidY([shadeView bounds]));
[shadeView addSubview:spinner];
[[self view] addSubview:shadeView];
To present:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2.0];
[spinner startAnimating];
shadeView.alpha = 0.7f;
[UIView commitAnimations];
And to hide:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[spinner stopAnimating];
shadeView.alpha = 0.0f;
[UIView commitAnimations];