Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to load a Nib for a UIView subclass

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?

like image 908
Adam Waite Avatar asked Mar 14 '13 09:03

Adam Waite


People also ask

How do I load a custom view in storyBoard?

Using a custom view in storyboardsOpen up your story board and drag a View (colored orange below for visibility) from the Object Library into your view controller. Set the view's custom class to your custom view's class. Create an outlet for the custom view in your view controller.

How to instantiate a UIView from a uinib file?

You can use the following two methods to load the contents (aka. the view hierarchy) of the file. let view = UINib(nibName: "CustomView", bundle: .main).instantiate(withOwner: nil, options: nil). first as! UIView view.frame = self.view.bounds self.view.addSubview(view) The snippet above will simply instantiate a view object from the xib file.

How do I use the contents of a xib file?

Using the contents of a xib file is a pretty damn easy task to do. You can use the following two methods to load the contents (aka. the view hierarchy) of the file. let view = UINib(nibName: "CustomView", bundle: .main).instantiate(withOwner: nil, options: nil). first as! UIView view.frame = self.view.bounds self.view.addSubview(view)

How do I add a custom view to a UIView?

If you don't like to handle views programmatically or you simply don't want to mess around with the loadView method, just remove it entirely. Next put the @IBOutlet keyword right before your custom view class variable. Open your storyboard using IB, then drag & drop a new UIView element to your controller and connect the custom view outlet.

Is it possible to remove Xib from a view class?

It is possible to leave out all the xib loading mechanism from the view instance. We can create a set of extensions in order to have a nice view loader with a custom view class from a xib file.


2 Answers

MyViewClass *myViewObject = [[[NSBundle mainBundle] loadNibNamed:@"MyViewClassNib" owner:self options:nil] objectAtIndex:0] 

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

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {     return [[NSBundle mainBundle] loadNibNamed:@"TopArea" owner:self options:nil].firstObject; } 

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. In TopArea.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.)

like image 175
Premsuraj Avatar answered Oct 05 '22 00:10

Premsuraj


If you want to keep your CustomView and its xib independent of File's Owner, then follow these steps

  • Leave the File's Owner field empty.
  • Click on actual view in xib file of your CustomView and set its Custom Class as CustomView (name of your custom view class)
  • Add IBOutlet in .h file of your custom view.
  • In .xib file of your custom view, click on view and go in Connection Inspector. Here you will all your IBOutlets which you define in .h file
  • Connect them with their respective view.

in .m file of your CustomView class, override the init method as follow

-(CustomView *) init{     CustomView *result = nil;     NSArray* elements = [[NSBundle mainBundle] loadNibNamed: NSStringFromClass([self class]) owner:self options: nil];     for (id anObject in elements)     {         if ([anObject isKindOfClass:[self class]])         {             result = anObject;             break;         }     }     return result; } 

Now when you want to load your CustomView, use the following line of code [[CustomView alloc] init];

like image 44
Ans Avatar answered Oct 05 '22 01:10

Ans