I am aware this question has been asked before but the answers are contradicting and I am confused, so please don't flame me.
I want to have a reusable UIView
subclass throughout my app. I want to describe the interface using a nib file.
Now let's say it's a loading indicator view with an activity indicator in it. I would like on some event to instantiate this view and animate in to a view controller's view. I could describe the view's interface no problem programmatically, creating the elements programmatically and setting their frame inside an init method etc.
How can I do this using a nib though? Maintaining the size given in interface builder without having to set a frame.
I've managed to do it like this, but I'm sure it is wrong (it's just a view with a picker in it):
- (id)initWithDataSource:(NSDictionary *)dataSource {
self = [super init];
if (self){
self = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"%@", [self class]] owner:self options:nil] objectAtIndex:0];
self.pickerViewData = dataSource;
[self configurePickerView];
}
return self;
}
But I'm overwriting self, and when I instantiate it:
FSASelectView *selectView = [[FSASelectView alloc] initWithDataSource:selectViewDictionary];
selectView.delegate = self;
selectView.frame = CGRectMake(0, self.view.bottom + 50, [FSASelectView width], [FSASelectView height]);
I have to manually set the frame rather than have it picked up from IB.
EDIT: I want to create this custom view in a view controller, and have access to control the view's elements. I don't want a new view controller.
Thanks
EDIT: I Don't know if this is best practice, I'm sure it's not, but this is how I did it:
FSASelectView *selectView = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"%@",[FSASelectView class]] owner:self options:nil] objectAtIndex:0];
selectView.delegate = self;
[selectView configurePickerViewWithData:ds];
selectView.frame = CGRectMake(0, self.view.bottom + 50, selectView.width, selectView.height);
selectView.alpha = 0.9;
[self.view addSubview:selectView];
[UIView animateWithDuration: 0.25 delay: 0 options:UIViewAnimationOptionAllowUserInteraction |UIViewAnimationOptionCurveEaseInOut animations:^{
selectView.frame = CGRectMake(0, self.view.bottom - selectView.height, selectView.width, selectView.height);
selectView.alpha = 1;
} completion:^(BOOL finished) {
}];
Correct practice still wanted
Should this have been done using a view controller and init with nib name? Should I have set the nib in some UIView initialisation method in the code? Or is what I have done ok?
If you want to keep your
CustomView
and itsxib
independent ofFile's Owner
, then follow these stepsFile's Owner
field empty.xib
file of yourCustomView
and set itsCustom Class
asCustomView
(name of your custom view class)IBOutlet
in.h
file of your custom view..xib
file of your custom view, click on view and go inConnection Inspector
. Here you will all your IBOutlets which you define in.h
filein
.m
file of yourCustomView
class, override theinit
method as followNow when you want to load your
CustomView
, use the following line of code[[CustomView alloc] init];
Answering my own question about 2 or something years later here but...
It uses a protocol extension so you can do it without any extra code for all classes.
I'm using this to initialise the reusable custom views I have.
Note that you can use "firstObject" at the end there, it's a little cleaner. "firstObject" is a handy method for NSArray and NSMutableArray.
Here's a typical example, of loading a xib to use as a table header. In your file YourClass.m
Normally, in the
TopArea.xib
, you would click on File Owner and set the file owner to YourClass. Then actually in YourClass.h you would have IBOutlet properties. InTopArea.xib
, you can drag controls to those outlets.Don't forget that in
TopArea.xib
, you may have to click on the View itself and drag that to some outlet, so you have control of it, if necessary. (A very worthwhile tip is that when you are doing this for table cell rows, you absolutely have to do that - you have to connect the view itself to the relevant property in your code.)Follow the following steps
UIView
.MyView.xib
.UIViewController
fromNSObject
in xib. See the image belowConnect the File Owner View to your View. See the image below
Change the class of your View to
MyView
. Same as 3.Here is the code to load the View:
Hope it helps.
Clarification:
UIViewController
is used to load your xib and the View which theUIViewController
has is actuallyMyView
which you have assigned in the MyView xib..Demo I have made a demo grab here
In Swift:
For example, name of your custom class is
InfoView
At first, you create files
InfoView.xib
andInfoView.swift
like this:Then set
File's Owner
toUIViewController
like this:Rename your
View
toInfoView
:Right-click to
File's Owner
and connect yourview
field with yourInfoView
:Make sure that class name is
InfoView
:And after this you can add the action to button in your custom class without any problem:
And usage of this custom class in your
MainViewController
:Well you could either initialize the xib using a view controller and use viewController.view. or do it the way you did it. Only making a
UIView
subclass as the controller forUIView
is a bad idea.If you don't have any outlets from your custom view then you can directly use a
UIViewController
class to initialize it.Update: In your case:
Otherwise you have to make a custom
UIViewController
(to make it as the file's owner so that the outlets are properly wired up).Wherever you want to add the view you can use.
However passing the another view controller(already being used for another view) as the owner while loading the xib is not a good idea as the view property of the controller will be changed and when you want to access the original view, you won't have a reference to it.
EDIT: You will face this problem if you have setup your new xib with file's owner as the same main
UIViewController
class and tied the view property to the new xib view.i.e;
The below code will cause confusion later on, if you write it inside view did load of
YourMainViewController
. That is becauseself.view
from this point on will refer to your customview