I am developing iPad application using UISplitViewController. I want to show/hide Master View Controller on demand. I have seen How to hide & unhide Master View Controller in SplitView Controller and Animate visibility of master detail controller of UISplitViewController, so I came up with something like this:
I have hideMasterView BOOL variable in my UISplitViewControllerDelegate and when I want to show/hide Master View I call:
hideMasterView = !hideMasterView;
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
[self.splitViewController willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0];
[self.splitViewController willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[self.splitViewController didRotateFromInterfaceOrientation:self.interfaceOrientation];
[self.splitViewController viewWillLayoutSubviews];
[self.splitViewController.view layoutSubviews];
}
completion:^(BOOL finished) {}];
And my delegate has method:
- (BOOL)splitViewController:(UISplitViewController *)svc
shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation{
return hideMasterView;
}
It works, but animation is not quite smooth. On hide everything works fine, but when Master View is being shown, Detail View is resized before sliding, leaving blank gray space on right and sliding on it afterwards.
How to fix this animation?
Related
my app is navigation based, i am adding a child view controller to one of my screens like so :
[self addChildViewController:_settingsVc];
[_settingsVc didMoveToParentViewController:self];
[self.view addSubview:_settingsVc.view];
[UIView transitionFromView:self.view toView:_settingsVc.view
duration:0.6
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished) {
_header_view.header_title.text = #"Settings";
}];
the view and animation shows great! and when i am returning like so from the presented child view controller :
[UIView transitionFromView:_settingsVc.view toView:self.view
duration:0.6
options:UIViewAnimationOptionTransitionFlipFromRight
completion:^(BOOL finished) {
_header_view.header_title.text = #"Friends Locator";
}];
i goes well too... the problem is if i am entering to the child view controller and hit the back button of the UINavigationBar then i can see the bar slides out and i got black screen.
how can i manage this?
The back button is do UINavigationController pop animation. You can try add a leftBarButtonItem that set a customView which is a UIButton, and add your own back animation in the button click event.
I have a button in my main view controller that pushes a navigation controller with an embedded view controller using a segue.
When the new view controller is presented, the navigation bar on it briefly appears under the status bar. (The status bar is not hidden.) The contents (which are relative to the top layout guide) are in the correct location. As soon as the animation is complete, it fixes itself.
When the view is dismissed again, the same thing happens: the main view controller briefly overwrites the status bar. For the main view controller, this is a little more significant as it's based on a UITableViewController; the entire table jumps. Again, when the animation is complete the view controller fixes itself.
I've tried turning off translucency on the navigation bar, but it only makes the problem more obvious. All of this works as expected on iOS 6.
I've uploaded a minimalist test case here: https://github.com/tewha/FlipTest
Another simple trick is do this:
In the MasterViewController
When is preparing for Segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[UIView transitionWithView:self.navigationController.view
duration:0.75
options:UIViewAnimationOptionTransitionFlipFromRight
animations:nil
completion:nil];
}
And when Unwind the AboutViewController
- (IBAction)aboutUnwind:(UIStoryboardSegue *)segue {
[UIView transitionWithView:((UIViewController *)segue.sourceViewController).view
duration:0.75
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:nil
completion:nil];
}
This is a bug in the layout system of iOS7. I found that reducing the height of the navigation controller's view (not the pushed view controller's!) by the status bar height and placing it in y = status bar height will help a lot, but there will still be a small flicker where the status bar "merges" with the navigation controller.
As a side not, see if the bug still exists in iOS7.1b1.
There is a Problem in the ios 7 with navigation bar ,Navigation bar appear over the views or showing gap between the nav bar and view , You can solved this problem with the help of following code
There has been a new property introduced in iOS 7 that lets you adjust the layout behavior as in previous versions of iOS. this code in your view controller, and you should be good The space your navigation bar takes up should be accounted for automatically
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Answer obtained from iOS 7 navigation bar jumping / stretching upon viewDidAppear
This is a bug in UK kit. Avoid using the standard methods
'performSegueWithIdentifier' or 'presentViewController'
Here I transition from one controller to another, then transition back in the delegate callback, using UIView transition animations.
-(void)photoButtonPressed:(NSNotification*)notification
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Media"
bundle:nil];
UINavigationController *navCon = [storyboard instantiateInitialViewController];
PhotoCaptureViewController *controller = navCon.viewControllers.firstObject;
controller.delegate = self;
CustomTabBarViewController *tabBarController = (CustomTabBarViewController*)self.tabBarController;
[UIView transitionWithView:self.navigationController.view duration:0.75 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
[tabBarController.parentViewController addChildViewController:navCon];
[tabBarController.parentViewController.view addSubview:navCon.view];
} completion:^(BOOL finished) {
[navCon didMoveToParentViewController:tabBarController.parentViewController];
}];
}
-(void)photoCaptureViewController:(PhotoCaptureViewController *)controller dismissButtonPressed:(UIButton *)dismissButton
{
CustomTabBarViewController *tabBarController = (CustomTabBarViewController*)self.tabBarController;
[UIView transitionFromView:controller.navigationController.view toView:tabBarController.view duration:1 options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
[controller.navigationController willMoveToParentViewController:nil];
[controller.navigationController removeFromParentViewController];
[controller.navigationController.view removeFromSuperview];
}];
}
This is a great read about container views Khanlou's blog post
I am developing an iPad app that should only support landscape orientation. I use these two methods to add a new child view controller to my container view controller:
- (void) assignFirstChildViewController:(UIViewController*)controller
{
self.currentChildViewController = controller;
[self addChildViewController:self.currentChildViewController];
[self.currentChildViewController didMoveToParentViewController:self];
[self.containerView addSubview:self.currentChildViewController.view];
}
- (void)assignNewChildController:(UIViewController *)childViewController
{
id currentChildViewController = self.currentChildViewController;
if(!currentChildViewController){
[self assignFirstChildViewController:childViewController];
}else{
[self.currentChildViewController willMoveToParentViewController:nil];
[self addChildViewController:childViewController];
__weak __block PTSBaseContainerViewController *weakSelf=self;
[self transitionFromViewController:self.currentChildViewController
toViewController:childViewController
duration:1.0
options:0
animations:^{
[UIView transitionFromView:self.currentChildViewController.view toView:childViewController.view duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve completion:NULL];
}
completion:^(BOOL finished) {
[weakSelf.currentChildViewController removeFromParentViewController];
weakSelf.currentChildViewController = childViewController;
[weakSelf.currentChildViewController didMoveToParentViewController:weakSelf];
}];
}
}
The problem is that the view of the child view controller is added in portrait orientation and it messes up the views as shown in the following image:
The green view is the view of the child view controller which as you can see is added in portrait mode. Instead of occupying the whole yellow view (which is the container view and it occupies the whole frame of the view controller beneath the grey top bar) it is being added in portrait mode and I cannot figure it why.
PS: I tried overriding shouldAutomaticallyForwardRotationMethods and shouldAutomaticallyForwardAppearanceMethods as written in the apple documentation but with no results.
As you'll see in Apple's documentation, you need to manually set the frame for the child view controller.
In a custom segue, I have the following simple transition:
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionWithView:src.navigationController.view duration:1
options:UIViewAnimationOptionTransitionFlipFromBottom
animations:^{
[src.navigationController pushViewController:dst animated:NO];
}
completion:NULL];
}
The content view animates fine. However, when executing the animation, the nav bar at the top has a messed up layout (buttons all crammed in the upper left corner, no title), popping into place only when the animation is finished. Anyone know what I've done wrong and how to fix it? Thanks!
Figured out my problem. The original code is indeed incorrect given how the UINavigationController works and interacts with the UIViewControllers it manages. (Annoyingly stuff like what I did in the OP can be found as a solution in older SO posts.)
Here's code that works for me (with one minor quibble):
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView transitionFromView:src.view
toView:dst.view
duration:1
options:UIViewAnimationOptionTransitionFlipFromBottom
completion:nil];
[UIView transitionFromView:src.navigationItem.titleView
toView:dst.navigationItem.titleView
duration:1
options:UIViewAnimationOptionTransitionFlipFromBottom
completion:nil];
[src.navigationController pushViewController:dst animated:NO];
}
Quibble: this will animate the navbar separately from the content view, so you have two pieces flipping instead of the whole screen. I had originally tried to do:
[UIView transitionFromView:src.navigationController.view
toView:dst.navigationController.view
But that fails because the 1) destination's navigationController property isn't even set yet until it's pushed onto a nav controller, and 2) even if it were I'd be referring to the same view! I forgot that
The view for a navigation controller is just a container for several
other views, including a navigation bar, an optional toolbar, and the
view containing your custom content...Although the content of the
navigation bar and toolbar views changes, the views themselves do
not...the navigation controller object builds the contents of the
navigation bar dynamically using the navigation items (instances of
the UINavigationItem class) associated with the view controllers on
the navigation stack. To change the contents of the navigation bar,
you must therefore configure the navigation items for your custom view
controllers. (docs)
Another "quibble" ?
I put
[src.navigationController pushViewController:dst animated:YES];
before
[UIView transitionFromView ...
so that the navigation controller was reachable within the destination's viewDidLoad method.
I built a app with storyboard, with an initial view controller, connected to many subsequent view controllers, connected sequentially, using cross dissolve segue. These work one swipes. All works fine. However, instead of being forced to use the basic segues, I want to have a custom segue that will slide the view controller content on and off the screen, much like the push for navigationControllers, but, being enabled to go left and right depending if one is going forward or backwards in the app.
I have set the segue to custom, and have created and saved a MySegue.h file. HOWEVER, I don't know how to code a custom segue that will slide one viewcontroller off the screen as the other slides on and back and forth as I move between view controllers.
Can anyone please provide me with come coding (it should be easy!) for a custom segue to move from one view controller to the next and back by sliding the screen on and off so I don't have to use the basic cross dissolve or standard flips offered in Xcode 4.2? I would be most grateful.
I was running into the same issue here, but I was using swipe gestures to go from one view controller to the next. Using the storyboard itself to set up segues was working fine, but when I needed a swipe to "go back" to the previous view controller, the animation went from right-to-left, instead of left-to-right. To fix that issue I did the following:
Embedded a Navigation Controller in the root view controller.
Used segues to push new view controllers.
When I wanted to "go back" to the previous view controller, I did not add a segue to the storyboard to push the previous view controller. Instead, I called the Navigation Controller's popViewControllerAnimated method whenever a back swipe occurred.
To create a custom segue that slides view controllers first create a class that extends UIStoryboardSegue, then override the perform selector. I just made something like this and it should work for you too. Here's my code:
#define kAnimationDuration 0.5
#import "CustomSlideSegue.h"
#implementation CustomSlideSegue
- (void)perform
{
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
[sourceViewController.view addSubview:destinationViewController.view];
[destinationViewController.view setFrame:sourceViewController.view.window.frame];
[destinationViewController.view setBounds:sourceViewController.view.bounds];
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if ( !self.slideLeft ) {
[UIView animateWithDuration:kAnimationDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[destinationViewController.view setCenter:CGPointMake(screenSize.height + screenSize.height/2, screenSize.height/2 - 138)];
[destinationViewController.view setCenter:CGPointMake(screenSize.width/2 + 127, screenSize.height/2 - 138)];
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview];
[sourceViewController presentViewController:destinationViewController animated:NO completion:nil];
}];
} else {
[UIView animateWithDuration:kAnimationDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[destinationViewController.view setCenter:CGPointMake(-1*screenSize.height/2, screenSize.height/2 - 138)];
[destinationViewController.view setCenter:CGPointMake(screenSize.width/2 + 127, screenSize.height/2 - 138)];
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview];
[sourceViewController presentViewController:destinationViewController animated:NO completion:nil];
}];
}
}
Then when you want to perform the segue use this code:
UIViewController *destination = [self.storyboard instantiateViewControllerWithIdentifier:#"some identifier"];
CustomZoomSegue *segue = [[CustomZoomSegue alloc] initWithIdentifier:#"segue vc identifier" source:self destination:destination];
[self prepareForSegue:segue sender:self];
[segue perform];
The CGPointMake calls are custom to my code (I used landscape orientation) but you should be able to change it to fit your needs. If you need further clarification or have any question let me know and I will try to answer.
NOTE: I use storyboards with no segue lines between the view controllers.
Why not just use a UINavigationController? This seems to be exactly what they're designed for.