CustomViewController's view's layout becomes wrong when added as subview - xcode

I have created a CustomViewController and layed it out in interface builder. Then I am all set to use the CustomViewController's view as a subview in another viewcontroller but when I add it to the other viewcontroller the layout of the custom uivewcontroller becomes wrong.
What can cause this? What is the propper way to do this?
The whole project can be found here https://github.com/agustr/STHLMPubCrawl just download and run (in an iphone 5 simulator). If there is any question about how it should look you can just move the initial view pointer to the 'place view controller cene'
this is the code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("GPPlaceViewController") as? GPPlaceViewController
if vc != nil{
vc?.view.layer.borderWidth = 4
vc?.view.layer.borderColor = UIColor.redColor().CGColor
self.GPPlaceView.layer.borderColor = UIColor.yellowColor().CGColor
self.GPPlaceView.layer.borderWidth = 2
vc?.view.frame.size = self.GPPlaceView.frame.size
self.GPPlaceView.addSubview(vc!.view)
}
else {
print("could not load GPPlacePageViewController from storyboard")
}
Any help is welcome.

I am unsure if this method of adding a VC's view to another view is wrong or outdated but I seem to remember it working at some point. I contacted apple and they told me to use a ContainerView. It is supposedly explained in detail in this talk 'Implementing UIViewController Containment' https://developer.apple.com/videos/wwdc/2011/.
The biggest problem I had when using the containment View was that you can not drag the segue in interface builder but you have to right click or controll click to point the segue to the appropriate place. Then you can treat that segue as any other in your parent viewcontroller that is to say the viewcontroller that contains the container view.

Related

Cocoa - Present NSViewController programmatically LIKE "Show option" in storyboard (Without being a Modal)

I am trying to present an NSViewController and there are 3 API's available.
presentAsModalWindow()
presentAsSheet()
present(....) for popover
But I want to simply present without the ViewController to become modal.
I found that in storyboard there is an option "Show". If you connect with any action then it will present the view controller and it will not be modal. But in code, I am not able to find a similar option.
NOTE: I want it should present exactly like how it did with presentAsModal without NewController being a Modal.
I found the solution. We need to create a new window and embedd in new Window controller.
let vc = MyViewController()
let myWindow = NSWindow(contentViewController: vc)
myWindow.makeKeyAndOrderFront(self)
let windowVC = NSWindowController(window: myWindow)
windowVC.showWindow(self)

Xcode Navigation Bar Goes under ScrollView?

Design mode everything is fine but in live Navigation Bar goes under the ScrollView How am I gonna solve this problem ? Please help
Again, without seeing any code at all it is hard to say, but I believe that the navigationBar isn't displaying at all. If you're presenting the UIViewController directly from another view, you're not instantiating the UINavigationController it is embedded in.
A solution would be to either create a segue in your storyboard from your presenting view to the UINavigationController, or add a storyboardId to the UINavigationController and instantiating as:
let nav = storyboard.instantiateViewControllerWithIdentifier("STORYBOARD_ID_HERE") as! UINavigationController
presentViewController(nav, animated: true, completion: nil)
If you can show some code on how the view is presented you'll receive better help, since it's impossible to know exactly what is wrong based on just one image.

How I can display another (change) ViewController when I press a button

in my xcode storyboard I have the standard viewController in which I have placed one Button with a Action Outlet.
I tried with an .xib which doesn't load. Further, I tried with an second ViewController in the Storyboard and a custom segue, but this also failed.
There is something I did wrong. Can anybody help me please?
If you are using Segues, you dont need to create a ViewController and try to display it this way. Just give a (unqiue) name to your ViewController (for Example if you dont want to use a "NavigationController" you should use "Modal" as Type. You should add a ViewController Class for each ViewController in Storyboard too.
So connect ViewController1 with your second View Controller and give them a name "loginModal".
Then in your IBAction, you can use:
self.performSegueWithIdentifier("loginModal", sender: self)
That should be all. If you want to send data between ViewControllers, you should use prepareForSegue. Check out my answer here, youll find more information about sending data with segues.
Sending data with Segue with Swift
You can try like this one
Put this code inside #IBAction button.
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let loginViewController = storyBoard.instantiateViewControllerWithIdentifier("LoginView") as loginViewController
self.presentViewController(loginViewController, animated:true, completion:nil)
Don't forget to set identifier's name in loginViewController.

How to embed a storyboard view controller in an NSScrollView OS X (10.10) to make a complex inspector view?

I'm looking at WWDC 2014 video, "212: Storyboards and controllers on OS X". In this video they claim that Pages UI does/could be arranged using Storyboards on OS X (see below).
However, in Pages UI the inspector view is very long and is embedded in a scroll view (you can verify this my two-finger scrolling in Page.app inspector view), also some inspector items are themselves contained in (some type of custom) disclosure view. It doesn't seem to be possible to embed a storyboard view controller in scroll view because there is no corresponding to "scroll view controller" class. Is that right?
How can a storyboard view controller's view be embedded in a scroll view on a storyboard?
I have tried direct embedding at run time, however, this is very hackish and does't work reliably (problems with auto-layout). This route still might be possible, but I wanted to get advice before going too far. For real UI it might be the case of falling back to XIBs.
- (void)viewDidLoad {
[super viewDidLoad];
// Swap the view controllers' view for a scroll view
NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:self.view.frame];
scrollView.documentView = self.view;
scrollView.drawsBackground = NO;
self.view = scrollView;
}
I think this answer is not really solving your problem but maybe helps understanding what is up with storyboards and scrollviews. I think Apple still has to fix some storyboard issues. I tried to use a collection view with storyboards, but it's impossible to connect the collectionViewItem in interface builder (which is happening automatically with xibs).
Here is an example with collection views:
Drag and Drop the collection view to a viewController. You will see a collection view and a collectionViewItem appearing. But the collection view item is NOT connected to the collection view. If you try this using IB, nothing happens.
In Identity inspector of IB assign a Soryboard ID. It's a random name which will be used in the code later. Here I am using "MyCollectionView"
If using swift, select your projects name in Module. The code is mostly the same for objC
Connect the collection view to the ViewController, containing the collection view
Do some coding to connect the Collection View item
class IVMyCollectionViewController: NSViewController, NSCollectionViewDelegate {
// manual connections to collection view (which is not working in IB)
#IBOutlet weak var collectionView: NSCollectionView!
class var sharedInstance : IVMyCollectionViewController {
struct Static {
static var instance:IVMyCollectionViewController? = nil
}
if Static.instance != nil {
return Static.instance!
} else {
let bundle = NSBundle.mainBundle()
let infoDict = bundle.infoDictionary!
let sbName = infoDict["NSMainStoryboardFile"] as String
let storyboard = NSStoryboard(name:sbName, bundle:bundle)!
let vcName = "MyCollectionView"
let sbInstance = storyboard.instantiateControllerWithIdentifier(vcName) as IVMyCollectionViewController
Static.instance = sbInstance
return sbInstance
}
}
// implement your controller
}
That means that some UI elements are not properly implemented yet. I would send a bug report to apple. There is still lots of things missing in interface builder.
Right now I would use a mixture of storyboard and xibs to abuse the storyboard in a way like above, by instantiating the connection in the constructor of the controller. You can use the storyboardID to launch views and other views or load from xibs. You can place viewControllers inside a storyboard without connections (segues) to create a pool of views that can be used like xibs. (A viewController is more or less the same like a xib)
// objC
DetailViewController* controller = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
or instantiate using the storyboardID like above.
Try to create a scroll view in storyboard. Create the views which you like to be shown in viewControllers for each view. Your scrollviews view controller should have a connection to the scroll view itself. In the following example the scroll view's outlet is named "self.contentView":
// instantiate a view controller for your scrolling view
self.scrollingViewController = [[ScrollingViewController alloc] initWithNibName:#"ScrollingView" bundle:nil];
// or do the same with storyboards by instantiating view controllers by ID
self.scrollingViewController = [myStoryboard instantiateControllerWithIdentifier:#"MyScrollingViewID"];
// Then set the view from the controller as content view
[self.contentView setDocumentView:self.scrollingViewController.view];
[self.contentView.contentView scrollPoint:NSMakePoint(0., self.scrollingViewController.view.frame.size.height)];
It's exactly like mixing up objective C and swift code. Apple seems to have entered a transition path which was not walked to the end.
In general you should think of View- or WindowControllers in storyboards is the same like a complete xib file. If you would like to use more views, use container views in storyboards. The FilesOwner in xibs is the viewController in storyboards. Container views offer you the ability to create a couple of views attached to a view controller. The segue mechanism is available for containers. I think the scroll view mechanism of OS X is not elegant. I struggled a lot with it, too.
Good luck!
Create the view that will be the document view of the scroll view.
Select that view
Go to Editor > Embed In > Scroll View
Based on this page of Scroll View Programming Guide for Mac.

How to use NSToolBar in Xcode 6 and Storyboard?

I've been trying to build on a Cocoa app that uses Swift and Storyboard in Xcode 6, but how can I use NSToolbar there?
In Xcode 5 and xib, you can add NSToolbar from within Object Library to any .xib files and then click on the added toolbar to expand it and drag and drop a connection from any items there to a AppDelegate.h file. In this way you can create a IBAction or IBOutlet connection. I confirmed that this can also be done if you use Swift and non-storyboard in Xcode 6. However, it looks like this is not the case in Xcode 6 and Storyboard environment.
I first created a project that uses Storyboard in Xcode 6, but then, I wasn't able to add a NSToolbar from within Object Library to a View Controller in Storyboard. So I added it to Window Controller's Window object in Storyboard. However, in this way I cannot create those connections from any items in the expanded toolbar to either AppDelegate.swift or ViewController.swift.
So my question is:
Is it feasible to create a storyboard app that uses NSToolbar?
If it is feasible, is the addition of NSToolbar to the Window Controller the proper way to use NSToolBar in Storyboard?
Finally, how can I create #IBOutlet and #IBAction connections there?
UPDATE
I found that the accepted answer by #GeorgeVillasboas only works for #IBAction. I am still looking for how to create an #IBOutlet connection...
I had this very same problem.
The solution works for both Objective-C and Swift projects.
Working with Storyboards on OSX, it creates an instance of NSWindow and segues to another NSViewController as its Window Content Segue, as you described.
On your ViewController, create a standard IBAction to receive the action when the toolbar is clicked. To wire it up with the NSToolbar, just control-drag (or leftClick-drag) from your NSToolbarItem to the FirstResponder object, as shown on the picture below.
This will open a HUGE list of available connections. Your IBAction will be on that list.
Just selected it and you're good to go.
Hope this helps!
Here's an answer that doesn't rely on run-time hook-ups - #cdalvaro's answer gets most of the way there for some applications, but isn't full, and it requires the ViewController to know about the artificial NSWindowController, which doesn't feel right.
Like #cdalvaro, the first step is to build your own subclass of NSWindowController, and to set the Storyboard WC to that class. You can then create all of your connections to and from the NSToolbar (both #IBOutlets & #IBActions) in the new WindowController. So far so good.
The last step, which I haven't seen anywhere else, is how to refer to the ViewController in the WindowController - you can't create an #IBOutlet to it - for the same reasons that we got here in the first place - you can't create references across scenes in the Storyboard. However, the WindowController must have a reference to the ViewController, and it does... self.window!.contentViewController! as! ViewController
Here's a complete WindowController with a checkbox that sets values in the ViewController, without the ViewController having to know anything...
class MyWindowController: NSWindowController {
var viewController: ViewController {
get {
return self.window!.contentViewController! as! ViewController
}
}
#IBOutlet weak var aSwitch: NSButton!
#IBAction func toolbarActionA(sender: AnyObject) {
println("toolbarActionA")
self.viewController.a = !self.viewController.a
self.aSwitch.state = self.viewController.a ? NSOnState : NSOffState
}
}
This helped me for the IBOutlet solution you are looking for:
https://stackoverflow.com/a/27555237/3398062
Update (explanation)
I discovered this thread because I was trying to create a Circular Progress Indicator inside the toolbar and I didn't know how to animate it from the ViewController since the IBOutlet was declared inside a custom WindowController.
Finally, I found the post that I have added above which describes how to access to IBOutlets from other classes.
In essence what I have done is the following:
Create a custom NSWindowController subclass (CustomWindowController) for the Window Controller so I can add the IBOutlet for the ProgressIndicator:
Code Example:
#interface CustomWindowController : NSWindowController
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#end
Then in the ViewController class, in the method I want to use to update the state of the Progress Indicator, I create and object of the custom Window Controller.
Code Example:
CustomWindowController *customWindowController = self.view.window.windowController;`
Finally, to change the state of the Progress Indicator there is only to call the method from the created custom object.
Code Example:
[customWindowController.progressIndicator startAnimation:sender];
or
[customWindowController.progressIndicator stopAnimation:sender];
This video helped me how to create a toolbar without writing a single line of code: https://www.youtube.com/watch?v=XSQocHG3IjA
You can add the 'Window Controller' item from the Object Library (if you don't have one), connect to a View Controller (where you want your toolbar to display) and follow the video! For custom Toolbar buttons add 'Image Button' item to the Toolbar just by dragging from the Object Library. Then you can pick an image for a button, set the size and so on...
Here is a general solution for the outlets and actions. it allows you to preform all the the same functions as an iboutlet would for a tool bar item and also allows you to set the button to a function instead of creating an ibaction. hope it helps :P
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
Here is a link to my question attempting to get a cleaner answer
http://www.stackoverflow.com/questions/27371439/use-nstoolbar-outlet-xcode-6-and-storyboard/27374449
but it looks like from the answers i have gotten so far this is the best option.
The same problem of IBOutlets also applies to KVO. One of the features of the NSSplitViewController is the canCollapse property for each split view item which supports KVO, but this is unusable in IB just like IBOutlets.
The only workaround I can see is to add a NSObjectController to each scene and when the scene loads, set the object controller's object to the object in the other scene (already loaded) that you want to reference.

Resources