How to make controls "tabable" when loaded from plugin in Cocoa app? - objective-c

I have an application thad loads in plugins that have their own UI.
There is an IBOutlet called ContainerView in my AppDelegate.
When the plugin loads, it puts its own view (that is stored in a xib in the plugin bundle) into the Container view like so
[ContainerView addSubview:viewFromPlugin];
When the view loads, everything is fine but when I press tab the only controls that get any focus are ones outside of the ContainerView and none of them inside it get focus.
I've tried setting the container view as the initialFirstResponder and I've tried hooking up the nextKeyView from the last button in the tab order to the ContainerView.
Thanks.

I've tried setting the container view as the initialFirstResponder and I've tried hooking up the nextKeyView from the last button in the tab order to the ContainerView.
Is that what you want to do? Make the container view the key view? It doesn't sound like it; it sounds like you want the plug-in view (or a view within it) to become the key view.
This section of the Apple documentation explains all of the different aspects of the key view loop. I believe you'll want to either set the nextKeyView of the container view as well as the view before it, or override the container view's nextValidKeyView method—possibly both. You might also try setting the previous view's nextKeyView directly to the plug-in view's nextValidKeyView, skipping over the container view entirely.

Did you try calling the becomeFirstResponder method on your ContainerView?
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/UIResponder/becomeFirstResponder
UIView classes inherit from UIResponder.

Related

UINavigationItem Prompt Animation Issue

I have two UITableViewControllers that are connected via a Show segue. The prompt property of UINavigationItem is set on both view controllers in Interface Builder. When the first view controller is shown, the prompt and navigation bar are both displayed properly, however, when performing a segue to the second view controller, the title and the back button animate undesirably. I have tried setting the prompts programmatically in the viewWillLayoutSubviews, viewDidLayoutSubviews, viewDidLoad, viewWillAppear:, and the viewDidAppear: methods of both view controllers, but I get the same effect.
Any ideas on how to resolve this issue? I don't want to resort to a custom view for the titleView because I prefer the stock functionality, but I am not able to figure out how to fix the undesirable animation.
Here is a video if the animation in question.
Well, it looks like this is an issue with the way that the UINavigationItem is laid out when showing the next view controller.
According to Catalina T. in an answer to a similar question, making two calls to set the hidden property of the navigation bar to true and then again to false in viewWillAppear: seems to get by this issue.

In Interface Builder, how can I add UIViews to a subview that is a part of a custom view I've created?

I am working to create a custom view for an iPhone app I'm creating. This custom view is a Popover dialog which is made up of a UIView which contains two images, a button to close the dialog, a label, and a UIScrollView. This view is named MDPopoverCard. I have these files as a part of my view:
MDPopoverCard.xib - The view as drawn up in Interface Builder.
MDPopoverCard.h - Defines a few IBActions and some other properties
MDPopoverCard.m - Implements some functions defined in the header
This is what it looks like in Interface Builder: http://cl.ly/2B0f2x3s1w1i0K2G0Q1r (sorry, I can't post an image yet as I'm new to stackoverflow)
There are a few properties defined in my .m and .h files that control whether the green button is displayed and what the text of the title label is.
I need to display a number of these dialogs in my app and I'd like to reuse this interface I've designed. I want to be able to add buttons and other form elements into the UIScrollView via Interface Builder. However, I have a problem:
Imagine that I have another view I'm drawing up in Interface Builder. I add a UIView to it and set its class to MDPopoverCard. I then drag a couple UIButton objects into my MDPopoverCard view. Here's an example of what it looks like in Interface Builder:
http://cl.ly/1X090h1t1q3f0i3E0917
This screenshot shows another view (the root view) that I've added my MDPopoverCard to. I've then added two buttons as subviews of MDPopoverCard.
These buttons do get properly nested in Interface Builder. However, when I run my app these buttons are added before any of the items that make up my MDPopoverCard view in the xib file. This means that the buttons are being added behind my popover dialog. That's the first problem.
The second problem is that I want these buttons and form elements to actually be added into the UIScrollView that's contained within the MDPopoverCard view, and not just right into the UIView's subviews array. Is there a way to specify this in Interface Builder? I'd really much rather draw buttons into my UIView and connect them to IBActions via Interface Builder than hand write every instance of these dialogs that I may need to display (several).
Any advice? Is there anything I can do to clarify the question?
Thanks for your help!
Formerly Xcode supported user-defined IB plugins for custom UI elements which you could just drag and drop into the XIBs the same way you do with built-in widgets. As of Xcode 4 this nice feature has been removed. (Thanks a lot, Apple.)
Currently I can only think of a hacky way to achieve what you described. What I would do is the following:
create an IBOutletCollection on your MDPopoverCard, e.g. embeddedControls
link it with every UI element (here: the buttons) you want to go inside the scroll view
implement the awakeFromNib in MDPopoverCard and explicitly reset the superview of all the views in embeddedControls to the scroll view in there
Hope this helps (although I haven't tried).

iOS 5 storyboard, programmatically determine path

I'm having trouble to achieve the following using a storyboard:
When setup is not done:
run app -> show settings view controller -> show main navigation controller
When setup is done:
run app -> show main navigation controller
So basically, I want the app to programmatically start with the settings view in certain cases, and otherwise skip right ahead to the main navigation controller.
I did manage to show the settings view with a modal style segue from the main navigation controller, but I don't know how to display it before the main navigation controller is displayed. Any ideas?
By default, the initial view controller from your main storyboard is instantiated and displayed automatically when your app starts up. To prevent this happening you need to remove the UIMainStoryboardFile setting from your info.plist file.
With no default view controller, you are now free to create one programmatically at app startup. See the UIStoryboard documentation. Use +storyboardWithName:bundle: to load the storyboard and then use –instantiateViewControllerWithIdentifier: to create the correct view controller. You will also need to create a main UIWindow and add the view controller's view to it just like you used to do with .nib based UI. Note that without the UIMainStoryboardFile setting a main window is not created for you - read the explanation.
I managed to do it a bit different:
Use a UINavigationController as the initial view controller.
Create a root view controller that will manage the decision of what to load.
Create a Storyboard Segues from the root view controller to the main view and to settings view, and give the segues proper identifiers.
Call the performSegueWithIdentifier with the proper identifier from your root view controller.
Just another solution, hope this helps.
I did something similar to amoshaviv, his advice is sound. I did it slightly different though, and I'll give some more info.
I created a custom MyInitialViewController class, derived from UIViewController, and made this the initial view controller.
In the storyboard file, I created modal segues with appropriate names to all (in my case three) possible 'real' first view controllers.
In the MyInitialViewController class, I implemented the
- (void)viewDidAppear:(BOOL)animated;
method, to first perform the check which view to switch to, and then do the correct
[self performSegueWithIdentifier:#"NameOfSegue" sender:self];
Effectively, this makes the MyInitialViewController nothing more than a switch performed when it's brought into view. I first tried doing this when loaded because I don't care for actually seeing this view, but that did not work, while viewDidAppear does.
To make this visually smooth, I tried the following. In the properties of the segues, I disabled animation. The view I left empty, and I gave it a background color matching to that of the startup image.

Cocoa Merging Custom Views

Currently, I have an NSStatusItem that, when clicked, shows a custom view below it. The view contains some information and text fields. What I need is for a separate custom view to merge with the first and appear below it, as in further down the screen, not on top or behind the original view. This needs to be a separate view because there are actually several custom view that will be appended depending on what the user does in the first view. I would like to be able to independently add or remove each of these without affecting the others. I've dug through apple documentation but I haven't found anything about putting one custom view inside another programatically.
NSView has an addSubview:positioned:relativeTo: method you can use to add and order views to appear above or below each other. Use superview: to access this method on a container from any of its subviews.
Edit:
Try adding both views to an NSSplitView with a hidden divider. To hide the divider, subclass NSSplitView and override the dividerThickness: method to return 0;

Drawing an "NSView" to a Custom-View - How? Am I taking the right approach?

I'm using Objective-C and Cocoa, whilst developing for Mac OS X - so not the iPhone/Cocoa Touch. (That said, I'd be interested if it was the same procedure for the iPhone)
I'm working on a preferences window for a simple app. I have a NSWindow with a toolbar - there are 5 different items on the toolbar, all of which need to bring up a different set of options.
So I set the NSToolbar and its items in Interface Builder, and then placed a custom view underneath the menu - taking up the rest of the window. My plan is to work out the interface too each of the NSToolbarItems options, and then draw the corresponding view on to the custom view when the specified NSToolbarItem is clicked.
I'm guessing that I simply create a NSView sub-class for each view, an empty xib in Interface Builder - set the xib to my custom NSView, code it as usual... But here's a few problems;
1 - Just how can I get the xib file to appear on the custom-view then? I have looked around and most articles don't seem to have this situation, or a situation I can relate too.
2 - When the window comes up, I want the default view to appear on the custom view. Once again, I'm guessing I just write that in the initialisation code for the NSWindow - its no big deal. It just goes back to question 1 though - how do I draw my NSView to the custom-view specified in Interface Builder?
I'd be really grateful for any help!
Cheers in advance.
So I set the NSToolbar and its items in Interface Builder, and then placed a custom view underneath the menu - taking up the rest of the window.
You can't have a menu inside of a window. You can have a pop-up button, which has a menu, but not a menu directly. Did you mean “toolbar” here?
You don't need to create a custom view for this. Make a tab view and set it to be tabless. Give it as many tab view items as you have toolbar items. In your controller, write an action method for each of the toolbar items, and in each action method, switch the active tab of the tab view.
You can activate different tabs in IB to populate them with views in IB. The active tab is saved in the nib, so make sure you set it back to the first tab before saving, so that the first tab is the one that's initially active when your app runs.
Just how can I get the xib file to appear on the custom-view then?
That question doesn't make sense.
Once again, I'm guessing I just write that in the initialisation code for the NSWindow - its no big deal.
You would only be able to do that if you have your own initialization code for the window, which you would only have if you have subclassed NSWindow. There are very few reasons to do that; unless you're making the window itself look different (not making an Aqua or HUD window), you should move that initialization code elsewhere, probably to the aforementioned controller (which should be the File's Owner of the nib).
It just goes back to question 1 though - how do I draw my NSView to the custom-view specified in Interface Builder?
A custom view in Interface Builder is a plain NSView (unless you explicitly change it to a subclass of NSView you create). However, you do not need one for anything you have described in your question.