How to segue push to a Navigation Controller from a UICollectionViewCell? - objective-c

In viewController1, I have a CollectionView and used the following code to create a segue to the selected item page.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "ToEventInfoSegue") {
let destination = segue.destination as! ViewController2
let cell = sender as! CollectionViewCell
destination.eventInfo = cell.anEvent!
destination.MainVC = self
}
}
Since the viewController2 is not currently embedded in a navigation controller, after the segue push, there is no navigation bar.
My question is in order to get the navigation bar, how do I implement the segue when the VC2 is embedded in a navigation controller?
Update
Tab Bar Controller -> Navigation Bar Controller -> VC1
VC1 -> (Currently no navigation bar controller) -> VC2
Update 2
After resetting the segue, I was able to get a navigation bar in StoryBoard. However, it seems that it is covered by the view. The navigation bar is not showing up. The back button does show up. I think the title is somehow on the bottom of the layer. The hierarchy looks like this.
The blue area is where the title of Navigation Bar is. However, as you can see it is covered and does not show when I run the app. The back button does show up

Based on your question what i understand is you need NavigationBar in your DetailViewController so for that you have to assign segue to your CollectionViewCell with DetailViewController like below screen shot.
I guess your storyboard flow like this:
What you need is assign segue from Cell to DetailViewController:
By doing this you can get your NavigationBar in your detail screen.
Hope this will help you to slove your problem.

Related

How to present view controller behind another view controller?

I am trying to present two view controllers. I'm trying to avoid presenting one after the other as this doesn't give a good user experience.
I'm using storyboards / segues to present the view controllers, each embedded in navigation controllers.
The behaviour should be:
View Controller 1 presents view controller 2 - but when view controller 2 dismisses I'd like view controller 3 to be the one showing to the user. And ideally an ability to also dismiss to view controller 1.
I understand I can accomplish this with child views. But I'd ideally like to learn how it can be done by manipulating the navigation stack.
I don't think you can do what you want with segue, but certainly you can do it with a little code...
This will (on a button tap, for example) perform a standard slide-in navigation controller animation directly from the current ViewController (call it vc1) to ViewController2, but "insert" ViewController3 into the stack. Tapping the Back button will take you from vc2 to vc3 to vc1.
#IBAction func didTap(_ sender: Any) {
guard let vc3 = storyboard?.instantiateViewController(withIdentifier: "vc3"),
let vc2 = storyboard?.instantiateViewController(withIdentifier: "vc2")
else { return }
let vcArray = [self, vc3, vc2]
self.navigationController?.setViewControllers(vcArray, animated: true)
}
If you want to go from vc2 back to vc1 and "skip over" vc3, in vc2 add (on a button tap, for example):
#IBAction func backToStartTap(_ sender: Any) {
self.navigationController?.popToRootViewController(animated: true)
}
As best to my understanding about your question, try out below method:
Present VC 3 from VC 1 and from VC 3 present VC 2 immediately(This can be done by putting the viewController present code in the ViewDidLoad() of VC 3).
So when you dismiss VC 2, VC 3 will be shown and on dismissing VC 3 , you will be redirected to VC 1.
VC means ViewController.
Presenting viewController in the ViewDidLoad() is really a bad idea.
You can present VC3 and add VC1.view and VC2.view as a subview of VC3's view and later you can remove VC1.view and VC2.view as you want and behaviour will be same as you are expecting.
You need to set your the viewcontroller you are going to present .modalPresentationStyle as .currentContext, and you need to set your current viewcontroller .definesPresentationContext as false

Putting a Navigation Controller inside a UIScrollView

I have a UIScrollView that houses three UIViewControllers so that I can swipe between them like the view setup in SnapChat.
In my ViewController on the very right of the UIScrollView I want the user to be able to select things and then navigate to a new page. So essentially I want the right-most UIViewController to be a Navigation Controller with a nav bar and and View Controllers I navigate to from this page should also have a nav bar and a Back button as the UIBarButtonItem in the top left as standard.
I went about it the normal way, just taking the View Controller and selecting "Embed In Navigation Controller" and looking at the storyboard it looks right, but if I run it, there's no nav bar at the top of the view controller.
I have the nav bar visibility set to "Show Navigation Bar" but still nothing.
Any help appreciated
Edit
The issue is more than likely to do with how I add the view controller to the UIScrollView which is as follows:
let settingsStoryboard = UIStoryboard(name: "SettingsView", bundle: nil)
let settingsViewController = settingsStoryboard.instantiateViewController(withIdentifier: "SettingsViewController")
self.addChildViewController(settingsViewController)
self.scrollView!.addSubview(settingsViewController.view)
So I'm only adding the view. So how would I add it as a Navigation Controller? Or can that be done?
The Problem you are facing is that you are adding your view controller directly inside the scroll view but you should add the navigation controller inside the ScrollView.
So go to story board create a StoryboardID for that navigationController which is attached to SettingsViewController and then replace the SettingViewController ID with your navigationController's Storyboard ID.
maybe use addChildViewController
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(5_0);

Hide a tab bar item but still display the controller

I will accept answers in both swift and objective-c as the translation is fairly easy.
I want to display a tab bar with a splash screen, but I don't want that splash screen to be in the tab bar items for selection.
My setup now (below) shows the landing screen as the first displayed controller when the tab bar displays. However, I want that tab bar item hidden. Only the other three tabs should be selectable by a user. How do I do this?
//Create and add landing view
navigation = UINavigationController()
landingView = WGMLandingViewController(nibName: XIBFiles.LANDINGVIEW, bundle: nil)
navigation.pushViewController(landingView, animated: false)
navigation.title = "Landing View"
controllers.append(navigation)
//Create and add library view
navigation = UINavigationController()
libraryView = WGMLibraryViewController(nibName: XIBFiles.LIBRARYVIEW, bundle: nil)
navigation.pushViewController(libraryView, animated: false)
navigation.title = "Learn More"
controllers.append(navigation)
//Create and add pad view
navigation = UINavigationController()
orderPadView = WGMOrderPadViewController(nibName: XIBFiles.ORDERPADVIEW, bundle: nil)
navigation.pushViewController(orderPadView, animated: false)
navigation.title = "Order Pad"
controllers.append(navigation)
//Create and add lookup view
navigation = UINavigationController()
partLookupView = WGMLookupViewController(nibName: XIBFiles.LOOKUPVIEW, bundle: nil)
navigation.pushViewController(lookupView, animated: false)
navigation.title = "Lookup"
controllers.append(navigation)
//Set up controller list
self.setViewControllers(controllers, animated: false)
Apple's existing APIs don't allow you to do this, but we it shouldn't too hard to sub-class UITabBarController and get it to do what you want.
Ok.. my original answer won't work these days.. or I've gone senile and it never worked and I did something else. *cough*
So anyway, you'll have to roll your own tab bar controller. It's not so hard (just time consuming) now that we have containment view controllers and you can still use the UITabBar.
Create a UIViewController (your tab bar controller) and stick a UITabBar and a UIView in it.
Create an outlet for the view (this is where your view controllers will go) and tab bar
Configure the UITabBar however you'd like it.
Set the delegate of the UITabBar to be your view controller and implement the didSelectItem method.
Create a method to load your splash screen view controller and stick in your viewDidLoad or where you want it.
Something like
- (void)loadSplashScreen {
// load in the child view controller
UIViewController *splashScreenController = ...;
[self loadChildViewController:splashScreenController];
// make sure nothing in the tab bar is selected
self.tabBar.selectedItem = nil;
}
Then also add code to load the appropriate view controller whenever the various tabs are selected
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
// logic to figure out which view controller you want based on `item`
// ...
UIViewController = ...;
[self loadChildViewController:viewController];
}
- (void)loadChildViewController:(UIViewController *)viewController {
[self removeCurrentTabController]; // remove the existing one, if any using whatever memory management techniques you want to put in place.
[self addChildViewController:viewController];
[self.tabView addSubview:viewController.view]; // where self.tabView is your outlet from step 2.
}

Segue Unwind back to the last specific View controller

Is there a way to have one button unwind back to a specific view controller? For example suppose I have ViewController A and B. Both modally segue to ViewController C. Now I understand how to segue unwind back to one of the previous view controllers (As was explained here) but how do I go back to the specific view controller that presented VC C?
So to sum it up, what I'm trying to figure out is...
If A segued to C then I want to unwind back to A when the button is selected. If B segued to C then I want to unwind back to B when the button is selected.
You should use the standard way to return from a modal segue. Put this in your 'back' button...
[[self presentingViewController] dismissViewControllerAnimated:YES];
This doesn't use the storyboard or a segue for the return, just code.
You could use the presentingViewController 'title' property to steer the unwind process to the desired originating ViewController. This solution would also allow you to pass data from your ViewController C to ViewControllers A and B.
1) Select the View Controller button (the yellow one) at the top of the storyboard canvas of ViewController A.
2) In the Attributes Inspector (View Controller section) give ViewController A a title.
3) Include the following code in ViewController A:
#IBAction func returned(segue: UIStoryboardSegue) {
// Don't need any code here
}
4) Repeat steps 1, 2 and 3 for ViewController B.
5) Override the prepareForSegue function in ViewController C as follows:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if self.presentingViewController!.title! == "ViewControllerATitle" {
let destination = segue.destinationViewController as! ViewControllerA
destination.someFunction(someArgument)
}
else if self.presentingViewController!.title! == "ViewControllerBTitle" {
let destination = segue.destinationViewController as! ViewControllerB
destination.someFunction(someArgument)
}
}

Back button not appearing on pushed UIViewController

I have a UITableViewController. When I click on a cell I want to push a new view. This works fine, but the new view doesn't have a back button. Why is this?
TableViewCode:
if([[NSUserDefaults standardUserDefaults] boolForKey:#"isLoggedIn"])
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
ProfileViewController* profileViewController = [[ProfileViewController alloc] initWithNibName:#"ProfileViewController" bundle:nil];
profileViewController.message = [NSDictionary dictionaryWithObjectsAndKeys:cell.textLabel.text, #"user_login", #"default", #"message_source", nil];
switch(indexPath.row) {
case kUsernameRow:
[self.navigationController pushViewController:profileViewController animated:YES];
[profileViewController release];
break;
case kAboutRow:
break;
case kTOSRow:
break;
}
}
If your table view controller is created from nib, its default title is #"" (notice: not nil, but an empty string).
Back button has a bug where it doesn't display if title of previous controller on navigation stack is an empty string, so inside your table view controller, you need to set title to either nil or some string in code, or some string in Interface Builder (can't set it to nil there afaik).
From Apple documentation:
The bar button item on the left side of the navigation bar allows for navigation back to the previous view controller on the navigation stack. The navigation controller updates the left side of the navigation bar as follows:
If the new top-level view controller has a custom left bar button item, that item is displayed. To specify a custom left bar button item, set the leftBarButtonItem property of the view controller’s navigation item.
If the top-level view controller does not have a custom left bar button item, but the navigation item of the previous view controller has a valid item in its backBarButtonItem property, the navigation bar displays that item.
If a custom bar button item is not specified by either of the view controllers, a default back button is used and its title is set to the value of the title property of the previous view controller—that is, the view controller one level down on the stack. (If there is only one view controller on the navigation stack, no back button is displayed.)
Check if your Navigation controller has navigation bar enabled. Click on Navigation bar under Navigation Controller in IB and check if 'hidden' is un-ticked. If it is ticked, the navigation bar will not be shown and so the back button would be invisible too.