I have a UINavigationController bassed sequence of screens. On one of the screens I want to replace the standard title with a custom TitleView. The custom view will be created with a nib file and will have an image and several labels.
Do I create a UIViewController w/ associated nib file, load the nib, and assign the .view property to the TitleView? Basically, how do I use a nib where I can layout the necessary elements and then assign the resulting view to the TitleView property?
Consider using UINib - it was exposed in iOS 4.0. It double perf since it caches the nib for you.
UINib *nib = [UINib nibWithNibName:#"TestView" bundle:nil];
UIView *myView = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0]];
The objectAtIndex refers to the top level views in the NIB - typically there's one (index 0) but if there's many, you need to provide the index.
Once you have the view you can assign it to the navigationItem titleView
self.navigationItem.titleView = myView;
[myview release];
EDIT:
If you need to get to the individual controls within the NIB, puts tags on them and access them via viewWithTag. See here:
http://useyourloaf.com/blog/2011/2/28/speeding-up-table-view-cell-loading-with-uinib.html
Create your custom view in Interface Builder & load it to a view(or you can create an IBOutlet iVar to point the view). Then just set the titleView to your custom view.
UIView * customTitleView = [[[NSBundle mainBundle] loadNibNamed:#"TitleView" owner:self options:nil] lastObject];
self.navigationItem.titleView = customTitleView;
[customTitleView release];
Related
I have xib with two CustomView (NSView *one, NSView *two),how i addSubview in AppDelegate?
self.content = [[ContentViewController alloc]
initWithNibName:#"ContentViewController"
bundle:nil];
[[[[self vertical] subviews] objectAtIndex:1] addSubview:[_content one]];
This way don't work.
Each view should be in it's own NIB file, as the NSViewController only has a single view instance variable.
So the answer is to split each view into it's own NIB; set the custom class correctly and then set the File Owner to NSViewContoller and connect the view from the controller to the custom view.
You then load each separately and add their views whereever you like (taking care to keep a reference to the NSViewController used to load the view).
I have a iOS 5 project nearly completed, but there's one View missing everywhere which is the same. It's an alternative to the standard NavigationBar, you can go "back" in the navigation hierarchy with a swipe and it's animating nicely.
Ok, because it's hard to do the layout by code I created the empty IB document (HeaderView.xib) where I have a view containing subview and etc.
I had the animation code before so I just created a UIView subclass ("HRAnimationView") (and wrote the name of it in the xib's inspectors "Custom Class" field, also hooked up the subviews to outlets) with a method:
- (void)loadAnimation {…}
and a second one (this is the delegate-method for finished animations):
- (void)animationDidStop:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {}
...this is where all the animation stuff happens and calling itself over and over till it's finished...
In the storyboard I have a subview with exact the same dimensions (and the outlet for it) and wanted to load the XIB (in the viewDidLoad-method of the corresponding controller) with:
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:#"HeaderView" owner:self options:nil];
HRAnimationView *view;
for (id object in bundle) {
NSLog(#"%#",object);
if ([object isKindOfClass:[UIView class]])
view = (HRAnimationView *)object;
}
self.headerView = view;
[self.view setNeedsDisplay];
[view loadAnimation];
BUT the headerView is EMTPY!! (also UIView *view didn't worked, nor owner:self.headerView)
…the Log just gives me:
<HRAnimationView: 0x3f1890; frame = (0 0; 240 49); autoresize = RM+BM; layer = <CALayer: 0x3f18d0>>
…
WHAT IS the problem?? There's also no compilation failure!
I don't get it, why is the xib TOTALLY worthless in my case?!
NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:#"HeaderView" owner:self options:nil];
after the above statement... try adding this
[self.headerView = [bundle objectAtIndex:0]
this should solve the problem
SOLVED!!!
I created a new ViewController and checked the "create with xib" box and deleted the view of the xib and copy&pasted the already set up view in there and in the ViewController I put the animation code in viewDidLoad.
Then loaded the hole thing in the viewDidLoad-method of each storyboard ViewController with:
UIViewController *ctrl = [[UIViewController alloc] initwithNibNamed:#"HeaderView"];
[self.headerView addSubview:ctrl.view]
(headerView is a IBOutlet to a view in every Storyboard so, that's basically the only thing to setup, NICE!)
another possibility would be:
Add subview using storyboard without external xib
or: http://forums.macrumors.com/showthread.php?t=749544
Looks like a Xib is useless without a corresponding ViewController, but should (strange.. whatever).
But thanks for your responses, hope someone now can find this if he/she has the same problem!
Can anyone tell me how (or direct me to info on) displaying a .xib (nib) on another .xib (nib).
How ever I wish to place it so I can programically move it around the main nib sort of like this (which obviously doesn't work)
- (void)drawRect:(NSRect)dirtyRect
{
NSRect customView = NSMakeRect(pos1, pos1, 200, 100);
[[NSBundle mainBundle] loadNibNamed:#"secondXib" owner:self];
NSRectFill (customView);
}
And I wish to do this for Mac OS X (Not iPhone). (By the way using xCode 4 incase it makes a difference)
You can easily load a view from another nib using NSViewController. In your nib you should just set File's Owner's custom class to NSViewController and hook up the view outlet of File's Owner to point to the view you want to load. You can then just do this:
//create an NSViewController and use it to load the nib
NSViewController* vc = [[NSViewController alloc] initWithNibName:#"YourNibName" bundle:nil];
//get the view from the view controller
NSView* loadedView = [vc view];
//release the view controller so we don't leak
[vc release];
//add the view as a subview of your main view
[mainView addSubview:loadedView];
//position the view
[loadedView setFrameOrigin:NSMakePoint(100.0, 100.0)];
You don't need to do anything in drawRect:. The subview will draw itself, and drawRect: will be called automatically if you move the subview.
You should read the View Programming Guide for Cocoa. It is critical to understanding how views work, and it is clear from your question that you do not yet have that understanding.
You should also read the Cocoa Drawing Guide.
Thanks a lot,
Another alternative ( which is basically the non programming way of doing it ), is to add a NSViewController object in your first xib, and set it to you use the nib name that you specify.
In your second xib, don't forget to set the class name in the "custom class" field on the view ( and NSViewController on file's owner ) else that won't work.
I am building a cocoa application with one main window controller with a xib. That xib contains many custom view classes. I would like to add an NSViewController to the xib, but i'm running into some trouble.
In interface builder I can drag the NSViewController into the xib, assign it its custom controller class, and assign its view to the appropriate view in the xib. Here's the problem: neither the initWithNibName:Bundle: or loadView get called.
What am I missing?
EDIT:
People seem to be misunderstanding the question so I'll clarify.
The window already has a view controller. What I am seeking to do is assign separate view controllers to several of the subviews. I need to know how to associate my NSViewController subclass with the appropriate NSView subclass (which is a child of the main window).
Or in other words, I am trying to use multiple NSViewController subclasses to controll many different custom views (one each) within a single .xib file. Those controllers and subviews have their own .xibs which should ultimately become visible in the same window.
The pattern I use for NSViewController is to have a xib per view controller. Then, when you need that view controller you alloc it and use the initWithNibName:Bundle: method. As soon as you use its view, loadView will get called.
Example:
self.editViewController = [[[MyEditViewController alloc] initWithNibName:#"MyEditViewController" bundle: nil] autorelease];
[self.window setContentView: editViewController.view];
I used to get stuck with that as well and gave up on that thing - the blue circle with a white bordered view in it from the IB palette. I now create my controllers from code and only set a reference in IB to the owning controller class via the file owner: right click the file owner, enter the class name in the Identity inspector and then make a connection from the file's owner view to the view.
In your code you then do at an appropriate initialisation point:
[self setMyViewController = [[MyViewController alloc] initWithNibName: #"MyView" bundle: [NSBundle mainBundle]]
For your specific case this could be in windowDidLoad method when your window is loaded from its nib and ready for work. You can then add the view to your windows content view. Also you might want to consider to have a 1:1 relation between view and view controller. It makes life a lot easier in terms of maintenance.
EDIT: Like #pcperini suggests in his comments you can use the palette component, but you'll still need to instantiate the controller in your code. If you want to use the palette component, create a property in your main controller or AppDelegate:
#property (...) MyViewController *myViewController;
Add the line of code to actually create the controller (see above). Then, using the bindings inspector bind the palette component to the myViewController property.
So, what you are missing is that you are actually not instantiating the controller object.
EDIT 2: Here's the code (the awakeFromNib is the method of the top controller). It creates two child controllers each handling a different subview:
- (void) awakeFromNib {
[[self startEndTopicHeader] setHeader: #"Event timeline boundary"];
[[self startDateHeaderView] setHeader: #"Event (start) date"];
[[self endDateHeaderView] setHeader: #"Event end date"];
[self setStartDateViewController: [[EventTimeViewController alloc] initWithNibName: #"EventTimeView" bundle: [NSBundle mainBundle]]];
[[[self startDateViewController] view] setFrame: [[self dummyStartView] bounds]];
[[self dummyStartView] addSubview: [[self startDateViewController] view]];
[[self startDateViewController] setParentController: self];
[self setEndDateViewController: [[EventTimeViewController alloc] initWithNibName: #"EventTimeView" bundle: [NSBundle mainBundle]]];
[[[self endDateViewController] view] setFrame: [[self dummyEndView] bounds]];
[[self dummyEndView] addSubview: [[self endDateViewController] view]];
[[self endDateViewController] setParentController: self];
}
So I have an NSTabView that I'm dynamically resizing and populating with NSView subclasses. I would like to design the pages in IB and then instantiate them and add them to the NSTabView. I got the programmatic adding of NSView subclasses down, but I'm not sure how to design them in IB and then instantiate them.
I think I got it. Let me know if this is not a good thing to do.
I made a new xib file, set its File's Owner to be an NSViewController and set its "view" to the custom view I designed in the xib.
Then you just need:
NSViewController *viewController = [[NSViewController alloc] initWithNibName:#"MyViewXib" bundle:nil];
NSView *myView = [viewController view];
#toastie had a really good answer. Mine is similar, but requires a bit more explanation.
Let's say you've already got a controller object and you don't want to instantiate a new controller object just to get at a view, and let's say that you're going to need multiple copies of this view (for example, you've designed a custom UITableViewCell in IB and you want to instantiate it again and again from your UITableViewController). Here's how you would do that:
Add a new IBOutlet to your existing class called "specialView" (or something like that). It may also be helpful to declare it as a (nonatomic, retain) property.
Create a new view xib called "SpecialView", and build the view however you like.
Set the File's Owner of the view to be your controller object.
Set the specialView outlet of File's Owner to be the new view.
Whenever you need a new copy of the view in your code, you can simply do the following.
(gratuitous text to get formatting working properly)
NSNib * viewNib = [[NSNib alloc] initWithNibNamed:#"SpecialView" bundle:nil];
[viewNib instantiateNibWithOwner:self topLevelObjects:nil];
[viewNib release];
NSView * myInstantiatedSpecialView = [[[self specialView] retain] autorelease];
[self setSpecialView:nil];
Yes, it's a bit more code than other ways, but I prefer this method simply because the view shows up in the designated IBOutlet. I retain and autorelease the view, because I like to reset the outlet to nil once I have the view, so it can be immediately ready to load a new copy of the view. I'll also point out that the code for this is even shorter on the iPhone, which requires one line to load the view, and not 3 (as it does on the Mac). That line is simply:
[[NSBundle mainBundle] loadNibNamed:#"SpecialView" owner:self options:nil];
HTH!