All,
I have met a problem with new UISplitViewcontroller in IOS8 for iPad. I have a UITableView in the storyboard in the detailViewcontroller and on clicking the cell, I should go to the another view called "detailinfo". I am current using a "show" segue.
However, the current segue just push on the right part. I wanna it show fullscreen , but I dont know how to make it, I tried using preferredDisplayMode property of the splitViewController , the result is it just hide the master view but didnt resize the detailView. I dont wanna using present as modal.
current way I am doing is
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier]isEqualToString:#"showStudentDetail"]){
if(self.traitCollection.horizontalSizeClass != UIUserInterfaceSizeClassCompact){
UISplitViewController *splitViewController = (UISplitViewController *)self.navigationController.parentViewController;
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
}
}
}
and in viewDidAppear, using
- (void)viewDidAppear:(BOOL)animated {
if(self.traitCollection.horizontalSizeClass != UIUserInterfaceSizeClassCompact){
UISplitViewController *splitViewController = (UISplitViewController *)self.navigationController.parentViewController;
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
}
}
This will work , but the masterViewController will "Jump out" which has a very bad visual effect.
Hope can get any help , thank you
UISplitViewController is a complex view controller which consists of two child view controllers. So when you use some segue which is added to any of the child view controller you ask child view controller to perform the segue. And this child view controller has partial control of active window.
In your case you need to ask the split view controller to perform the segue. So you should add the segue to your split view controller which handles active window. This way you will have the fullscreen option.
UPDATE
If you dont wanna using present as modal and want to avoid "Jump out" effect you can hide master using animation
UISplitViewController *splitViewController = [self splitViewController];
[UIView animateWithDuration:0.25 animations:^{
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
} completion:^(BOOL finished) {
[splitViewController showDetailViewController:vc sender:nil];
}];
Related
Here is the controllerviews' structure in storyboard:
[tableviewcontroller] [tableviewcontroller] [FilterMenuController]
| |
[navigationcontroller] [navigationcontroller]
| |
[tabbarcontroller]
Now in second tableview controller I have following code to present a slide in overlay filter menu view. Which will be over TabbarController.
- (IBAction)didPushFiterButton:(UIBarButtonItem *)sender {
FilterMenuTableViewController *tlc = [self.storyboard instantiateViewControllerWithIdentifier:#"FilterMenuController"];
[tlc.view setFrame:CGRectMake(320, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.tabBarController addChildViewController:tlc];
[self.tabBarController.view addSubview:tlc.view];
[tlc didMoveToParentViewController:self];
[UIView animateWithDuration:0.3 animations:^{
[tlc.view setFrame:CGRectMake(40, 0, self.tabBarController.view.frame.size.width, self.tabBarController.view.frame.size.height)];
}];
}
Now, I want that if push on a button within the filter view, filter view will be gone and the tableview will be reloaded. I wrote a custom segue. But really messed. Either tableview is not reloading or navigation bar and tabbar is lost.
Can you give me some idea how to write this segue? or how to accomplish this?
Thank you.
Just fixed this problem. Hope it can help others.
Basically, I should not have tried to use a segue to solve this problem. Delegate should be the cure.
So set the table view controller as the FilterViewController's delegate. When button within FilterViewController is pushed. The delegate method in TableViewController will remove the filterView and reload the data.
I have seen this topic (iOS Storyboard Back Button) and more about this subject, but I still cannot have my back button appear on screen :
I have got 2 viewControllers, the two of them have a navigationController, the "father" controller has the button bar item set to "back" as a plain text, the second viewController appear well with a modal segue, or with "show detail (replace)" segue, but nothing appear on the navigation bar to come back... Would you know why?
Here is a capture :
Thanks
EDIT :
with a custom transition, and when presenting the controller via the navigator in the code, the back button is not here anymore... would someone know why?
When I comment out presentViewController:secondViewController, the back button is here, but the custom animation is not triggered anymore, there is the normal transition set in the storyboard.
Here is my method :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(#"segue descr %# : ", [[sender class] description] );
if ( [[segue identifier] isEqualToString:#"second"] ){
//SecondViewController *secondViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"SecondViewController"];
SecondViewController *secondViewController = [segue destinationViewController];
secondViewController.transitioningDelegate = self;
[self.navigationController presentViewController:secondViewController
animated:YES
completion:nil];
Modal and show detail segues don't use a back button, because they are like independent views.
The idea is that those those views are only showing extra information or details about something and you can close them programmatically when you need to go back to the previous view.
A show or push segue will give you the back button in your navigation controller, because that segue is meant to be more like a sequence of views.
When you push a View Controller, you get the back button for "free" without having to write extra code. When you present a modal View Controller, you need to add your own way of dismissing the modal view. Since you have a Navigation Controller, your easiest route is probably to add a UIBarButtonItem to the navigation bar, and have that bar button call dismissViewControllerAnimated:completion: in your UIViewController subclass.
in my project i would like to use the MMDrawerController plugin ( https://github.com/mutualmobile/MMDrawerController ) but i have a problem. In the project i'm using the storyboard so i have read this post http://pulkitgoyal.in/side-drawer-navigation-for-ios/ but the plugin doesn't works.
I have the root view controller that calls another view (the drawer) with a segue and so it use this method (as written in the guide)
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"DRAWER_SEGUE"]) {
MMDrawerController *destinationViewController = (MMDrawerController *)segue.destinationViewController;
// Instantitate and set the center view controller.
UIViewController *centerViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"FIRST_TOP_VIEW_CONTROLLER"];
[destinationViewController setCenterViewController: centerViewController];
// Instantiate and set the left drawer controller.
UIViewController *leftDrawerViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SIDE_DRAWER_CONTROLLER"];
[destinationViewController setLeftDrawerViewController: leftDrawerViewController];
}
}
When the destionation view is loaded i see only the centerView without the Side drawer controller. Why?
Thanks in advance.
Did you tried opening the side view controller on some action on center view controller?
e.g.,
- (IBAction)menuTapped:(id)sender {
[self.mm_drawerController toggleDrawerSide:MMDrawerSideLeft animated:YES completion:nil];
}
this will open up the side drawer for you.
EDIT:
Else simply write the following code in your Center view controller's viewDidLoad,
self.mm_drawerController.openDrawerGestureModeMask = MMOpenDrawerGestureModePanningCenterView;
self.mm_drawerController.closeDrawerGestureModeMask = MMCloseDrawerGestureModePanningCenterView;
You can change the gesture mode as per your requirement.
Reusable button bars? gets me part of the way here, but now I'm having trouble with the "back button" requirements.
I need a layout solution that:
will work on iOS 5.0 and 6.0
has a custom view at the top with several buttons; this view should be reusable across every screen (scene), as opposed to duplicating the buttons manually in Interface Builder for each scene.
has a custom "back" button in that top custom view. With the design I have to implement, I cannot just use the default navigation bar
works well with the UINavigationController; when the user taps the "back" button, the main view controller (with the button bar) should stay, but the child view controller representing the actual scene content should go back to the previous scene.
The problem currently is that the "back" button won't change the child controller--it changes the parent controller, returning to the previous scene before the scene with the button bars. I've tried this several different ways. I'm not sure if I'm not doing it right, or if it can't be done.
One possibility is to implement my own "back" functionality, keeping a stack of child view controllers and manually changing them when the user taps "back." This is awkward, however, and poor design compared to using UINavigationController.
Perhaps I am going the wrong way with this. I can't accept duplicating the button bar across every single scene in Interface Builder... but perhaps I should create it programmatically, and then I can easily call that code from each and every scene. Then I would have "normal" view controllers, and using UINavigationController would be easier. But before I go that route and completely scrap what I have so far, I wanted to see if there was another way.
Here's an overview of some parts of my solution:
I created a ButtonBarController, laying out the Storyboard with a UIView for the buttons I wanted, and a UIView for the content pane. I also layered a button with the app logo (to go to the app's main screen) on top of a back button.
Then I created a controller for each of those other screens. In those subscreens/child view controllers, I would first add a UIView at the correct size to fit in my content pane, and then would add all the other controls I wanted. I had all of those child view controllers inherit from another controller, which took care of a few common tasks--such as procuring a reference to the button bar controller, and code to help resize the views for 3.5" versus 4" screens.
I created a changeToControllerWithIndex method; I call this when the app loads, when the user clicks one of the buttons in the main button bar to change scenes, or when anything happens in a scene requiring another scene change. I overload this method to provide two additional pieces of information: providing an NSDictionary with any extra information the child view controller needs, and to tell it whether this is a top-level scene, or whether we need a back button.
(Note: it's important to set the Storyboard ID for those child view controllers in the Identity Inspector. I kept accidentally setting the Title in the Attribute Inspector instead)
- (void)changeToControllerWithIndex:(NSInteger)index {
[self changeToControllerWithIndex:index withPayload:nil isRootView:YES];
}
// This is the method that will change the active view controller and the view that is shown
- (void)changeToControllerWithIndex:(NSInteger)index withPayload:(id)payload isRootView:(BOOL)isRootView
{
if (YES) {
self.index = index;
// The code below will properly remove the the child view controller that is
// currently being shown to the user and insert the new child view controller.
UIViewController *vc = [self setupViewControllerForIndex:index withPayload:payload];
if (isRootView) {
NSLog(#"putting navigation controller in");
childNavigationController = [[UINavigationController alloc] initWithRootViewController:vc];
[childNavigationController setNavigationBarHidden:YES];
[self addChildViewController:childNavigationController];
[childNavigationController didMoveToParentViewController:self];
if (self.currentViewController){
[self.currentViewController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentViewController toViewController:childNavigationController duration:0 options:UIViewAnimationOptionTransitionNone animations:^{
[self.currentViewController.view removeFromSuperview];
} completion:^(BOOL finished) {
[self.currentViewController removeFromParentViewController];
self.currentViewController = childNavigationController;
}];
} else {
[self.currentView addSubview:childNavigationController.view];
self.currentViewController = childNavigationController;
}
[self.currentView addSubview:childNavigationController.view];
//We are at the root of the navigation path, so no back button for us
[homeButton setHidden:NO];
[backButton setHidden:YES];
} else {
//Not a root view -- we're in navigation and want a back button
[childNavigationController pushViewController:vc animated:NO];
[homeButton setHidden:YES];
[backButton setHidden:NO];
}
}
}
Then I have an overloaded method to set up each individual view controller... some require a little more preparation than others.
- (UIViewController *)setupViewControllerForIndex:(NSInteger)index {
return [self setupViewControllerForIndex:index withPayload:nil];
}
// This is where you instantiate each child controller and setup anything you need on them, like delegates and public properties.
- (UIViewController *)setupViewControllerForIndex:(NSInteger)index withPayload:(id)payload {
UIViewController *vc = nil;
if (index == CONTROLLER_HOME){
vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Home"];
} else if (index == CONTROLLER_CATEGORIES){
SAVECategoryViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:#"Categories"];
if (payload) {
child.currentCategory = [(NSNumber *) [(NSDictionary *)payload objectForKey:ATTRIBUTE_CAT_ID] integerValue];
} else {
child.currentCategory = CATEGORY_ALL;
}
vc = child;
} //etc for all the other controllers...
payload = nil;
return vc;
}
I mentioned my difficulty with managing the "back" navigation. The above code ensures the navigation controllers maintain a proper "back" history, starting fresh whenever we use one of the button bar buttons to change screens. When we do use buttons inside a child controller to navigate from scene to scene, this is how we can go back:
- (IBAction)backButtonPressed:(id)sender {
[childNavigationController popViewControllerAnimated:YES];
if ([[childNavigationController viewControllers] count] <= 1) {
//Root view
[homeButton setHidden:NO];
[backButton setHidden:YES];
}
}
I think you need to implement at least one custom container view controller - the root view controller. That would be the one to host the custom button bar. Below the button bar you would add a UINavigationController the manage your other VCs. Look at this for starters:
#implementation RootVC
//...
- (void)viewDidLoad
{
self.navVC = [[UINavigationController alloc] initWithRootViewController:someOtherVC];
self.navVC.navigationBarHidden = YES;
self.navVC.view.frame = ...;
[self addChildViewController:self.navVC];
[self.view addSubview:self.navVC.view];
[self.navVC didMoveToParentViewController:self];
}
- (void)backButtonTouched:(UIButton *)button
{
[self.navVC popViewControllerAnimated:YES];
}
Hey guys i`m trying to present a modal view controller inside an application with a tab bar controller. The problem is, every time the new view is presented, it on top of my tab bar.
I need to keep my tab bar even when the view is presented. Like google maps application does with his toolbar at the bottom of the screen.
How can i do that?
Thank you
By default, a modal view controller is meant to take up the entire screen (on an iPhone/iPod, at least). Because of this, it covers whatever you have on screen at the time.
A view controller presented via modal segue is meant to live on its own. If you want to keep your Navigation and TabBar, then just use a push segue to present the new ViewController. Remember to use this kind of segue, your presenting controller needs to be part of a UINavigationController already.
Use this to push a ViewController. If it is a UINavigationController it will push its linked RootViewController by itsself.
Create a viewController to push: (Using Storyboard)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
or (Using Code/Nibs)
LoginViewController *viewController = [[LoginViewController alloc] init]; //initWithNibNamed in case you are using nibs.
//in case you want to start a new Navigation: UINavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
and push with:
[self.navigationController pushViewController:vc animated:true];
Also, if you are using Storyboards for the segues you can use this to do all the stuff. Remember to set the segue identifier.
[self performSegueWithIdentifier:#"pushLoginViewController" sender:self]; //Segue needs to exist and to be linked with the performing controller. Only use this if you need to trigger the segue with coder rather than an interface object.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"pushLiftDetail"]) {
[[segue.destinationViewController someMethod:]];
segue.destinationViewController.someProperty = x;
}
}
I think you'll need to add a UITabBar to the modal view and implement/duplicate the buttons and functionality that your main bar has. The essence of a modal window is it has total control until it is dismissed.
You might try putting your UITabBarController into a NavBarController, but I'm not certain that this will work.
UITabBarController -> NavBarController -> Modal View