Programmatically swapping subviews in iOS - ios

I'm building an iPad app and want to switch one of my subviews for another by pressing a button. I've been reading the documentation and this guide:
View Controllers: How to switch between views programmatically?
But I keep getting errors and the animations doesn't really happen, the views just switch immediately.
I'll paste some code below for context. I have a main view which has in it a sub uiview. In the sub uiview, there is another view. I want to swap the other view with another.
self.settingsViewController = [[GHPSettingsViewController alloc] initWithNibName: #"GHPSettingsViewController" bundle: nil andParent: self];
UIView *outerView = [self.containingView viewWithTag:0];
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration: 100.25f];
[UIView setAnimationDuration: UIViewAnimationCurveEaseInOut];
if (self.settingsViewController.view.superview == nil) {
// Flip Out Old View
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.containingView cache:YES];
[self.settingsViewController viewWillAppear: YES];
[outerView removeFromSuperview];
[self.containingView insertSubview: self.settingsViewController.view atIndex: 0];
[self.settingsViewController viewDidAppear: YES];
}
[UIView commitAnimations];

Related

IOS stop UIbutton to take its own place after animation completed

I have set the animation like seen in below image. In which UIbutton move from left to right and then top to bottom. Animation work correctly but after completion of animation UIButton comes to its original place before the segue perform. so, it's not look good. I want to set that after the completion of animation UIButton can't come to it's own place before segue .
Here is my try with Image.
//Move button Left to Right
- (IBAction)btnEasy:(id)sender {
Easy=YES;
NSLog(#"your x is: %f ", self.btnEasy.frame.origin.x);
NSLog(#"your y is: %f ", self.btnEasy.frame.origin.y);
x1=self.btnEasy.frame.origin.x;
y1=self.btnEasy.frame.origin.y;
CGRect screenRect = [[UIScreen mainScreen] bounds];
[UIView animateWithDuration:1.150 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.btnEasy.frame = CGRectMake(screenRect.size.width/1.80, self.btnEasy.frame.origin.y, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height);
[self performSelector:#selector(btneasyanimation) withObject:self afterDelay:1.160 ];}
completion:^(BOOL finished) {
}];
//Move Button top to Bottom
if (Easy==YES) {
if (isiPad2 || isiPadAir || isiPadRatina) {
//[self.view layoutIfNeeded];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:1.0];
[_btnEasy setFrame:CGRectMake(self.view.frame.origin.x+290, self.view.frame.origin.y+900, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height)];
[UIView commitAnimations];
}
else if (isiPhone4s) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:1.0];
[_btnEasy setFrame:CGRectMake(self.view.frame.origin.x+92, self.view.frame.origin.y+428, self.btnEasy.frame.size.width, self.btnEasy.frame.size.height)];
[UIView commitAnimations];
}
}
[self performSelector:#selector(segueeMethod) withObject:self afterDelay:1.160 ];
Image :-
If you are not placing directly the button given it the frame, thus using autolayout (autoresize will end with the same effect). You need to explicitly use autolayout, retain a reference to your constraints and update them (you can search here how to do that) and then set the UIView animation block [button layoutIfNeeded]
You can see a detailed answer about it in this answer
There is an easy and quick way that will work with your current implementation. Provided you know exactly where you want the view to be once the animation is done, you can do the following:
in UIView animateWithDuration: ... assign the final transform (position & orientation) of the view in the completion block, i.e.:
completion:^(BOOL finished) {
// Assign views transform and appearance here, for when the animation completes
}
Hope that helps.

Changing animation from view to view

I have a tabbar application with 4 tabs and a navigation bar hooked to one. On the tab with the navigation bar I have a button that brings you to a new page. I also have one that brings you back to the tab page, but I have a problem. When going back to the tab page the animation is going the wring way. I did this all with storyboards so no coding. I looked around and want to put this in the code:
- (void) pushController: (UIViewController*) controller
withTransition: (UIViewAnimationTransition) transition
{
[UIView beginAnimations:nil context:NULL];
[self pushViewController:controller animated:NO];
[UIView setAnimationDuration:.5];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationTransition:transition forView:self.view cache:YES];
[UIView commitAnimations];
}
But i have no idea how and where to put it in.
Take a look at this Apple guide to creating a custom segue. Your perform code would look something like this:
- (void)perform {
[UIView beginAnimations:nil context:NULL];
[self.sourceViewController.navigationController pushViewController:self.destinationViewController animated:NO];
[UIView setAnimationDuration:.5];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationTransition:transition forView:self.view cache:YES];
[UIView commitAnimations];
}
Then in your storyboard, set the type of the segue to Custom, and then enter the name of your custom segue class.

IOS Animations without navigation controller

In my app im showing different screen this way:
info = [[Info alloc]initWithNibName:#"Info" bundle:nil];
[self.view addSubview:info.view];
Info is a subclass of UIViewController, so i just create it and add it as a subview of the current view.
When i want to dismiss it i just do:
[self.view removeFromSuperview];
Im not sure if this is the right way of doing it, but yesterday apple has published on app store another app that do the same to display views.
My question is, how can i animate the transition between views, so when i call addsubview it do the animation?
I tried this:
info = [[Info alloc]initWithNibName:#"Info" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
forView:info.view
cache:YES];
[self.view addSubview:info.view];
[UIView commitAnimations];
But its not working, this dont do anything.
It's not the right way to manage view hierarchy. You should use view controller methods for this (addChildViewController: & removeFromParentViewController). Then you can use method transitionFromViewController:toViewController:options:animations:completion: (or something like that) to do various animations.
to add a view controller's view use this
ChildViewController * child = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
forView:info.view
cache:YES];
[self.view addSubview:child.view];
[UIView commitAnimations];
[self addChildViewController:child];
[child release];//for NON ARC
to remove view use this...
for (UIViewController *childVC in [self childViewControllers])
{
[childVC removeFromParentViewController];
}
[self.view removeFromSuperview];// YOU CAN ADD ANIMATIONS HERE
[self removeFromParentViewController];
HOPE this will help you, It is working fine for me....
You can use CATransition for that kind of animation without using navigationcontroller below is the code
Info *infoViewController = [[Info alloc]init];
CATransition *transition = [CATransition animation];
transition.duration = 0.50;
transition.timingFunction =
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromRight;
UIView *containerView = self.view.window;
[containerView.layer addAnimation:transition forKey:nil];
[self presentModalViewController:infoViewController animated:NO];
Like this you can animate the view from left to right without using navigationcontroller.
You can give UIView Block Animation a shot. Something like this:
[UIView animateWithDuration:.25 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
requiredView.frame = CGRectMake(0, 300.0, 400.0, 180.0);
} completion:^(BOOL finished)
{
}];
You can set the view's frame and position it outside the viewing co-ordinates and then change the frame accordingly to animate the UIView.

XCode IOS Beginner UIViewController Class change with button

I am new to programming, I have been searching all night long and tyring to figure this out for a long time. Cant.... I dont want to use a navigation Controller but what I am trying to do is this.
So I have two classes in my project. Class1 and Class2. Now there is a button in Class1. If this button is pressed, I want the screen to go to Class2. The closest I got was creating a parent class but when I do that, the button remains on both classes.
- (IBAction)addScheduleB:(id)sender {
[UIView beginAnimations:#"View Curl" context:nil];
[UIView setAnimationDuration:1.00];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
if (self.firstScreen.view.superview ==nil){
if(self.firstScreen==nil) {
self.firstScreen = [[FirstScreen alloc] initWithNibName:#"FirstScreen" bundle:nil];
}
[self.config1.view removeFromSuperview];
[self.view insertSubview:self.firstScreen.view atIndex:0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
[self.config1.view removeFromSuperview];
[self.view insertSubview:self.firstScreen.view atIndex:0];
[sender setTitle:#"Switch To DVR"];
}
else{
if(self.config1 == nil){
self.config1 = [[Config1 alloc] initWithNibName:#"Config1" bundle:nil];
}
[self.firstScreen.view removeFromSuperview];
[self.view insertSubview:self.config1.view atIndex:0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[self.firstScreen.view removeFromSuperview];
[self.view insertSubview:self.config1.view atIndex:0];
[sender setTitle:#"Switch To TV"];
}
[UIView commitAnimations];
}
I want to remove the parent class and have just the two classes.
Is it possible to have a button inside class1 when pushed will take me to class2???
There is a 7 minute tutorial on YouTube Here. That shows how to move from one view to another using a button without storybord so you will be able to lern the code to move from one class to another.
I hope this helps. As for being a beginner if you look around youtube you will find lots of tutorials to help you learn. :)
EDIT: this does not use a navigation controller
i hope This solution helps You
just make object from Class2 and when Button1 Pressed add Class2's object.View as subview to Class1.view
Good Luck
Try something like :
- (IBAction)flipViews {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.6f];
if ([saisieCompleteView superview])
{
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
[saisieCompleteView removeFromSuperview];
[self.view addSubview:saisieRapideView];
[self.view sendSubviewToBack:saisieCompleteView];
}
else {
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[saisieRapideView removeFromSuperview];
[self.view addSubview:saisieCompleteView];
[self.view sendSubviewToBack:saisieRapideView];
}
[UIView commitAnimations];
}
The both saisieCompleteView and saisieRapideView must be subview of your principal view.
you may pop the another view with modal flip transition:
[self presentViewController:Class2 animated:YES completion:^{
// Some code on completeion
}];
to dismiss the Class2 view:
[self dismissViewControllerAnimated:YES completion:^{
//code
}];
if you don't want to go out of current view controller, you may flip it this way:
BOOL toShowSecond = YES;
...
[UIView transitionWithView:self.view
duration:1.0
options:(toShowSecond?UIViewAnimationOptionTransitionFlipFromLeft:UIViewAnimationOptionTransitionFlipFromRight)
animations:^{
if(toShowSecond) {
firstView.hidden = YES;
secondView.hidden = NO;
} else {
firstView.hidden = NO;
secondView.hidden = YES;
}
}
completion:^(BOOL finished){
toShowSecond = !toShowSecond;
}];

Animating removeFromSuperview

I'd like to animate the transition from a subview back to the super view.
I display the subview using:
[UIView beginAnimations:#"curlup" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
[self.view addSubview:self.mysubview.view];
[UIView commitAnimations];
The above works fine. It's going back to the super view that I don't get any animation:
[UIView beginAnimations:#"curldown" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view cache:YES];
[self.view removeFromSuperview];
[UIView commitAnimations];
Is there something different I should be doing to get the subview to animate when removed?
If you're targeting iOS 4.0 upwards you can use animation blocks instead:
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];
(above code comes from Apple's UIView documentation)
I think you need to do forView:self.view.superview instead, to be consistent with what you are doing when you are adding, because in this case the self.view is the child, and so you would need to do it on the parent.
JosephH answer in Swift:
UIView.animateWithDuration(0.2, animations: {view.alpha = 0.0},
completion: {(value: Bool) in
view.removeFromSuperview()
})
Although approach with sending removeFromSuperview message from animation completion block works fine for most cases, sometimes there is no way to prevent a view from immediate removal from view hierarchy.
For example, MKMapView removes its subviews after it receives message removeAnnotations, and there is no "animated" alternative for this message in the API.
Nonetheless the following code allows you to do whatever you like with a visual clone of a view after it's been removed from superview or even deallocated:
UIView * snapshotView = [view snapshotViewAfterScreenUpdates:NO];
snapshotView.frame = view.frame;
[[view superview] insertSubview:snapshotView aboveSubview:view];
// Calling API function that implicitly triggers removeFromSuperview for view
[mapView removeAnnotation: annotation];
// Safely animate snapshotView and release it when animation is finished
[UIView animateWithDuration:1.0
snapshotView.alpha = 0.0;
}
completion:^(BOOL finished) {
[snapshotView removeFromSuperview];
}];
Example below:
func removeSpinningGear(cell: LocalSongsCollectionViewCell) {
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.curveLinear, animations: {
cell.spinningGearBtn.alpha = 0.0
}) { _ in
cell.spinningGearBtn.removeFromSuperview()
}
}

Resources