I have a UIViewController that adds other UIViewControllers as children so that I can use their views to create a menu hierarchy. The following images represent my current interface.
The interface before displaying the menu:
The interface after displaying the menu:
The following explains my hierarchy:
In AppDelegate I create an instance of MainContainerViewController and set it as the window's rootViewController. The view controller acts as a container allowing me to add Chile view controllers.
In MainContainerViewController I create an instance of CenterViewController and add it as the rootViewController of an UINavigationController. I add the navigation controller as a child view controller, adding the navigation controller's view as a subview of MainContainerViewController. I also create an instance of LeftMenuViewController, adding it as a child view controller and inserting its view below the navigation controller's view. This allows me to tap the UIBarButtonItem of CenterViewController and show the menu by sliding the navigation controller's view to the right.
I have added an UIScreenEdgePanGestureRecognizer to the navigation controller's view which allows me to show the menu by sliding CenterViewController's view off to the right.
I have added an UITapGestureRecognizer to the navigation controller's view which allows me to close the menu by tapping the navigation controller's view.
I want to be able to use an UIPanGestureRecognizer to allow the user to interactively close the menu similar to how Slack allows, if you're familiar with their mobile UI.
I added the pan gesture recognizer to the navigation controller's view, just as I did with the two aforementioned gesture recognizers. However, I can't get the UIScreenEdgePanGestureRecognizer and UIPanGestureRecognizer to play well together. I have tried implementing combinations of UIGestureRecognizerDelegate methods without success. I feel a little lost with gesture recognizers, and I don't know where to start with trying to get these gesture recognizers to play well.
I have followed Apple's example, adapted to my requirements. If the menu is not displayed, then the UIPanGestureRecognizer should allow the UIScreenEdgePanGestureRecognizer to open the menu.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if leftMenuState == .hidden {
if gestureRecognizer == panGestureRecognizer && otherGestureRecognizer.view!.isDescendant(of: gestureRecognizer.view!) {
return true
}
}
return false
}
What I expect:
Ability to display menu by using UIScreenEdgePanGestureRecognizer
Ability to tap CenterViewController and have menu close
Ability to pan CenterViewController and close menu
What happens:
Menu is not opened by panning with UIScreenEdgePanGestureRecognizer because UIPanGestureRecognizer receives events
Menu is opened by UIBarButtonItem
Menu is closed by UIBarButtonItem or UITapGestureRecognizer
What do I need to do to enable the intended functionality?
Related
What exactly does the Presentation option(in Attribute Inspector) do in StoryBoard for Cocoa.
It gives two options to select from
Single
Multiple
P.S When googled the title, results are related to powerpoint presentation
The presentation style affects "Show" segues. Possibly it affects other segues too, but I only tested a Show segue. I tested on OS X 10.10.5 (Yosemite) with Xcode 7.1.1.
If a window controller's presentation style is "Multiple" (the default), then a Show segue to the window controller always loads a new instance of the window controller from the storyboard. This means that you can end up with multiple instances of the window controller at once, each with its own window on the screen. By default those windows will stack on top of each other, so it won't be obvious what happened until you move or close one.
If a window controller's presentation style is "Single", and an instance of the window controller has already been loaded from the storyboard, and that window controller still exists (presumably because its window is still on screen), then a Show segue to that view controller will not create a new instance. Instead, the Show segue will bring the existing window controller's window to the front.
This behavior is useful if you want behavior like, say, Xcode's Devices window, where there can only be one such window. You create a "Devices" menu item in the Window menu in your storyboard, and connect it to the Devices window controller in the storyboard with a Show segue. Set the Devices window controller's presentation style to Single. Now the menu item will never create a second Devices window controller if one already exists.
You'll probably want to somehow set the window's excludedFromWindowsMenu property to true, so it doesn't appear twice in the Window menu (because by default it appends itself to that menu). You could, for example, use a subclass of NSWindowController that sets it:
class DevicesWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
window?.excludedFromWindowsMenu = true
}
}
View controllers also have a presentation style, because you can also connect Show segues to view controllers. A Show segue connected to a view controller automatically creates a window controller to contain the view controller at runtime. The window controller's presentation style is effectively set to the view controller's, so you get the same singleton behavior if you set the view controller's presentation to Single.
As far as I can tell, the storyboard setting has no corresponding public property or method you can use in code.
If you connect the Show segue to a storyboard reference (new in Xcode 7), then the segue ignores the presentation style of the destination window controller, and acts as if it were "Multiple". This happens even if the destination is actually in the same storyboard as the reference.
Is it possible to do navigation within the same window in a mac application ?(Like it is possible in ios apps).I want to show each view in the same window instead of opening different windows on a button click.
e.g When a user clicks a button then the next page should be loaded in the same window.(The next page will have nothing in common with the current page.)
You may use Tab View for easy switching between views on a same window.
UPDATE:
You may also customize your tab view , make it tabless (In the attributes inspector set style to tabless) and use your buttons to switch between views.
You may take help from the following link : http://devcry.heiho.net/2012/01/nstabview-tutorial.html
OR
You may add or remove subviews from your window on button clicks, using
[[yourWindow contentView] addSubview: yourSubview]; // Add subview to window
[yourSubview removeFromSuperview]; //Remove subview
UPDATE:
Steps to swap between views using a tabless tab view.
Drag a NSTabView to your xib.
Set the no. of tabs in attribute inspector to no. of views you want.
Design each view of the tab as per your requirement.
Now in the attribute inspector of tabview, set style to tabless.
Now drag the buttons you want to use for swapping between views. Suppose Button0 and Button1 are for 1st and 2nd view of your tab view.
Create a IBOutlet for your NSTabView in your .h file. Bind it to the referencing outlet of you tabview.
IBOutLet NSTabView* tabview;
Set a IBAction for both your buttons in your .h class file.
In the button action method for button1, use
- (IBAction)button1clicked:(id)sender
{
[tab selectTabViewItemAtIndex:0];
}
Similarly in button2 action method use:
[tab selectTabViewItemAtIndex:1];
In this way you can have any no. of views and you may select any view on button click using
[tab selectTabViewItemAtIndex:(index of the view you want to load)];
In general you want to google for view swapping.
There are tons of examples out there. Some from Apple and lots elsewhere.
Much of it is very similar to iOS.
You need to read the docs a bit too.
Understand NSView and how to load views from nibs, how to create view objects in code, how to add a subview and how to remove a view.
There are many approaches to having different views for different reasons. The right approach is a combination of style, experience and what your app actually needs to do.
Cocoa includes NSBox, NSTabView, and lots of others. Those two can be configured to not display any visual indication that they are containers.
You will also need to understand at least a little about NSWindow to understand its content view (the root container of other views generally)
I can't get the standard back button of iOS into a navigationBar because I can't find it in the Object Library, so can I do it with code or something else?
I just want the normal, standard, blue back button - you know which I mean.
To "automatically" have a back button you need first have a UINavigationController. Then you need to take a different UIViewController and add it as the root view controller in UINavigationController's init method:
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:someOtherViewController];
Be sure to also set a title for someOtherViewController, usually in it's viewDidLoad or initializer. I'll tell you why this is important in a second:
self.title = #"Some other VC";
Then take a second UIViewController and push it onto your navigation controller:
[navigationController pushViewController:anotherViewController animated:YES];
You now have two UIViewControllers on your navigation stack: someOtherViewController and anotherViewController.
Your view will now have a back button with "Some other VC" in it. This is the title of the view controller that was just moved out of view:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
http://simplecode.me/2011/09/04/an-introduction-to-uinavigationcontroller/
I would also suggest reading up on how UINavigationControllers work and searching this site a bit more for customizing the back button. There are plenty of threads about it.
You can't add the back button yourself. The back button is part of the Navigation controller. If you embed a Navigation controller into your view(s), the back button will appear and be populated by the name of the previous view.
If you're using storyboards select your view controller, then in top menu choose "editor" -> "embed in" -> "navigation controller".
Edit: Here is an exmaple.
I'm running Xcode 7.2. This was driving me crazy, but I figured it out. Here are all the pieces you need to make the Back button appear (make a test project to prove it):
1) You have to have a Navigation Controller and it has to be set to be the initial view controller. So add the Navigation Controller, you will import two tables. Click on the Navigation Controller and on the properties list, check the box that reads "Is Initial View Controller". You will now see and arrow pointing to this view.
2) In our case we want a ViewController and not the included / connected TableViewController, so delete the TableViewController (RootController) and add a new ViewController.
3) Connect the Navigation Controller to the new ViewController by clicking on the top bar of the Navigation controller and orange circle with the arrow pointing left. Hold the Control button on your keyboard down and click and drag from the orange circle to the ViewController and let go. When given the list of options on how to connect the two views, select 'root view controller'.
Done! Now you the functioning navigation bar and you automatically get the back arrow on all segues added. Test this. Add another ViewController and connect to it with a button on the existing ViewController. Use the Control-click-drag approach from the button to the newest ViewController. Select the 'show' option for the new segue you created.
Run it. You'll see the back option has automatically appeared when you click the button and moved to the newest ViewController.
This is all provided by the Navigation Controller, but only when you make another controller the RootController. Happy navigating!
It's easy enough to drag and drop bar button items onto a view controller's navigation bar in a storyboard in Interface Builder. In this way, you can set the leftBarButtonItem and rightBarButtonItem outlets of the view controller's navigation item. But there's also a backBarButtonItem outlet, and it's not obvious at all how to set it. How can I set a custom back bar button item using Interface Builder?
Select the view controller whose navigation items you want to change. The black bar displaying the identity of the view controller changes to an iconified tray of its referenced objects.
Drag and drop a bar button item from the object library onto the tray.
Right-click on the view controller's navigation item in the main object tray on the left-hand side. Wire up the newly added button as the navigation item's backBarButtonItem outlet.
Select the bar button and configure it in any way you choose with the Attributes Inspector.
As #wcochran noted above, when working with viewControllers pushed onto a navigationController's stack, the backBarButtonItem outlet is already wired and can't be changed. Furthermore, selecting the child VC's navigationItem and changing the Back Button text in IB doesn't do what you would expect.
Now you might think that replacing the child VC's backBarButtonItem would solve the problem, but it doesn't. Confusingly, if you want to set the title of the back button of a child VC, you have to set the back button title of its parent (!), like so:
- (void)viewWillAppear:(BOOL)animated // in the parent VC!
{
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
}
This won't do anything on the parent VC. In fact, if the parent is the navigationController's RootViewController, there won't be a back button at all. But the child will inherit (or pick up) the back button you've created.
This only applies to the immediate child VC, so if you want to maintain the label down through the navigationController's stack you need to set it on each parent.
Thanks to #wiliz in #iphonedev for explaining this to me.
As #AdamBlock noted above, you have to set things right in the parent VC.
He shows how to do this programmatically. It is also possible to do this in interface builder.
Select the parent VC
Select the navigation Item
Open the Attributes inspector
Set the title for the Back Button.
In Interface Builder, you can change the Navigation Item back button's title.
Programmatically, you can set a custom back button in your view controller's viewDidLoad method. In this example we set the button's image to an image named "customImage.png":
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Custom" style:UIBarButtonItemStyleBordered target:self action:nil];
// Set custom image here
backButton.image = [UIImage imageNamed:#"customImage.png"];
self.navigationItem.backBarButtonItem = backButton;
}
I am really new to iPhone development and I need help setting up my views.
I have a view that is named FirstViewController.xib and a controller class for this view.
In my MainWindox.xib I have setup a root controller with a moveToNextView function that is connected to the options bar button item.
So when I click on this item the current view switches to the first view and I am able to swticht back. That works fine so far.
The navigation bar at the top of the screen from the MainWindow.xib is displayed in the first view, too. But when I open FirstViewController.xib there isn't any navigation bar defined (but on build&run it is displayed).
This is a problem for me because I want to add a save bar item to the first view. How do I solve that?
Assuming you have a UIViewController (or UIViewController subclass) that is a child of a UINavigationController. Note, I'm using storyboards so your results may vary when using xibs.
If you do not see a UINavigationBar on the interface, try manually changing the simulated metrics.
Drag a Navigation Item onto the view (anywhere). You should now have a place to enter the title in the interface builder.
Now you can drag Bar Button Items onto the nav bar.
You have to do it from code. Add to your FirstViewController class viewDidLoad method:
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Save" style:UIBarButtonItemStyleDone target:self action:#selector(doSave:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
Just drag a bar button item onto your nav bar in Interface Builder. Xcode automatically wires it up then you can use it like anything else...