Using custom View with Storyboard without adding it twice - ios

I'm using Storyboard and trying to reuse a View for different ViewControllers.
For that, I created a custom .xib (MyCustomView.xib) and class (MyCustomView) as suggested pretty much everywhere.
In my Storyboard I set the custom view to be of type MyCustomView.
In MyCustomView.xib, set First Responder to MyCustomView.
In MyCustomView.m, I added the following method:
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])){
UIView *myCustomView = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil] objectAtIndex:0];
[self addSubview: myCustomView];
}
return self;
}
Problem is, [self addSubview: myCustomView] adds a new MyCustomView to existing MyCustomView, so the view is added twice.
How can I get rid of one of the two?
EDIT
My question is not really clear, so I thought some screen caps would help.
Here is my Storyboard with a custom view. Custom class is set to MyCustomView.
(I also added a grey background and a label for testing purpose only)
Now, in MyCustomView.xib, I set File's owner to be of Class MyCustomView:
And add outlets for title Label and imageView:
With the initWithCoder method as written above, this works fine, except when I debug I can see this:
So self is of course of type MyCustomView, as chosen in the Storyboard, but it contains 2 subviews :
First is the test label from my storyboard
Second is the view from MyCustomView.xib, itself containing a Label and image view. That's this view I want to get rid of.

What is self ?
Here, it is the MyCustomView you just instantiated. So, you're adding a new UIView (not MyCustomView) to your new MyCustomView instance created by the initWithCoder method.
initWithCoder is the method called when loading your storyboard view.
If you want to instantiate a new MyCustomView in your MyCustomViewController you have to call
MyCustomView *newInstance = [[MyCustomView alloc] init];
[self addSubview:newInstance];
Where self is the instance of MyCustomViewController in your storyboard.
EDIT
OK, I understand better your question.
If you want to load the MyCustomView nib file, you don't need to create a class for it (except if you have specific variables you want to access in it.
Just do what you're doing here, but in the view controller, which will be the self. :)
You might want to have a look at : How to load a UIView using a nib file created with Interface Builder
EDIT 2
Ok, I think I get it :
delete the MyCustomView in your Storyboard.
create a class MyView or whatever which you attach to the view named "View" in your Storyboard.
in the init method of your class you instantiate your MyCustomView nib
add the resulting UIView to the views stack like you did it.
self will be MyView (present in the Storyboard), MyCustomView won't appear in the storyboard but created programmatically in the init method of MyView.h
You will have to add constraints programmatically. Here is a post that can be helpful: Adding View Programatically With Auto Layout Gives 'NSGenericException', reason: 'Unable to install constraint on view

Related

How to subClass a view which created from an Xib file

I have a viewA is loaded from Xib.
My question is that how to subClass this viewA.
Every time when the my SubClass inited, and call [super init], it will return [viewA class].
Similar situation happened in Storyboard, when I want to subClass a viewController which loaded from Storyboard.

xcode interface builder : nib is not being displayed while placing inside other nib

I have developed a custom UIView with nib file such that I can reuse it whenever needed. Now the thing is I have a nib of a UIViewController and I am drag and drop a Dummy UIView inside it and changing the Class Name to custom view's class name. This works fine when I run my application. I can see the Custom View in my screen on runtime. But I can not see it in Interface builder. So, my question is, is it possible to see the custom view's layout in view controller's nib through interface builder?
You can't load a nib from inside another nib.
You could get around this by leaving the view in your view controller's nib as a placeholder, then loading the custom view's nib in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
UINib *customViewNib = [UINib nibWithNibName:#"CustomView" bundle:nil];
CustomView *customView = [[customViewNib instantiateWithOwner:self options:nil] objectAtIndex:0]
customView.frame = self.placeholderView.bounds;
[self.placeholderView addSubView:customView];
}

UIView in nib not connecting to IBOutlets

I am adding on screen a UIView in this way:
ViewController2 *detailViewController = [[ViewController2 alloc] initWithNibName:#"MJDetailViewController" bundle:nil];
[self presentPopupViewController:detailViewController animationType:MJPopupViewAnimationFade];
since MJDetailViewController is a nib and holds a UIView, I have created a custom class of UIView and selected it as class for the view in the inspector. When the window is loaded, the UIButtons do actions in the class that has been created, but the IBOutlets don't work. Even if I decided to add a UIButton programmably, it doesn't appear on screen. Why is this?
I thought of changing the UIView to a UIViewController, but it won't work because you can't present it with an animation.
I suspect you haven't set up the nib objects correctly.
In addition to setting the class of your UIView subclass you need to configure the 'File's Owner' and connect the views to it. You do this by selecting the file owner and setting its' class (this is done the same as setting the view's class). In your case the class of the file owner should be ViewController2.
Hopefully this screenshot explains this better:
Also you can simplify things a bit by using UIViewController nib naming conventions. If you give your nib the same file name as the view controller then you can specify nil as the nibName:. For example, if you name your nib ViewController2.xib then you can do this:
ViewController2 *detailViewController = [[ViewController2 alloc] initWithNibName:nil bundle:nil];
This approach is preferable as it means that the nib filename becomes an implementation details which calling code does not need to know about.

Load custom UIView with XIB from a View Controller's view using IB

I have a custom UIView (MyCustomUIView) which is built using Interface Builder. I'd like to place this custom view in MyViewController's view, which is also designed using IB. I've placed an UIView as a subview in MyViewController's XIB and set it's class to MyCustomUIView. The problem is, when I run the code, only a blank view appears. (When I instantiate MyCustomUIView in code, it displays well.)
I'm only overriding the initWithFrame: method the following way in MyCustomUIView.m:
- (id)initWithFrame:(CGRect)frame
{
[[NSBundle mainBundle] loadNibNamed:#"MyCustomUIView" owner:self options:nil];
self = self.view;
return self;
}
What should I do to make the view load properly? How should initWithCoder: look like?
You are correct. IB uses initWithCoder. initWithCoder should look very similar to your other init methods:
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
// CUSTOM INITIALIZATION HERE
}
return self;
}
Once you assign your class within IB, you won't need to instantiate it from the bundle unless I'm misunderstanding your intention.
Do not put anything in the view part of the view controller in IB. Instead, set the nib name for the view controller in IB to the name of the nib containing the view. In the nib containing the view, set the file's owner to the view controller class and hook up its view property to the view.
The result will be that when the view controller is instantiated, if it is instantiated from the nib (which you have not proved is what's really going to happen, but let's just say it is), it will find the nib and load the view from it.
Basically the rule is that it makes no difference where a view controller comes from, it will go through the same steps looking for its view in the same order, as I explain in my book:
http://www.apeth.com/iOSBook/ch19.html#_view_controller_and_view_creation
and in this webcast:
http://www.youtube.com/watch?v=zIufcKpDIRo

Programmatically created UIViewController loading an Interface builder view.xib file

How to load an interface builder created view from a programmatically created UIViewController? I'm using Objective-C.
I was able to start with a reference project that did not use the interface builder, so I have no storyboard. I have successfully loaded views programmatically, but would like to be able to load some that were interface builder created.
More detail: I have 2 view controllers A and B. I'm currently in A. I click a button and in that button handler I load Viewcontroller B like this:
self.viewControllerB = [[ViewControllerB alloc] init];
[self.navigationController pushViewController:viewControllerB animated:YES]
I manually created a ViewB with a .m and .h. If I use an initWithFrame wherein i define a bunch of controls and lay them out programmatically, I can successfully call it as described above.
I add a new file to the project, which is a UIView which brings it up in the builder. Drop a TableView onto the view, and now I just want to see this load.
I named the xib ViewB.xib, I set the Class to ViewB like the pic below shows (In answer 1)
Whenever you need to load a view from a .xib use this:
First make a nib for the view in interface builder, and be sure to set its custom class to your view's class, see the picture:
and then load it in your code like this:
MyCustomNibView *myView;
NSArray *topLevelItems = [[NSBundle mainBundle] loadNibNamed:#"MyCustomNibView" owner:nil options:nil];
for (id view in topLevelItems) {
if ([view isKindOfClass:[MyCustomNibView class]]) {
myView = (MyCustomNibView *)view;
break;
}
}

Resources