i have a .nib file in my application that i would like to show it to the user as a "popup" window.
I would like to have a result like this :
Here you can see an empty "popup" window with an X for closing.To be accurate this is an MT popup Window but sadly you can only load it with html and not with a view , like a .nib file.
Does anyone know how i could create a popup window like this to show a .nib file or have a ready 3rd party solution?
A custom UIView is what you want my friend.
So create a class that has the super UIView.
Create a an objective-c Class call. For example I call mine CustomView
Your Header(.h)
#import <UIKit/UIKit.h>
#interface CustomView : UIView
#end
Your class(.m)
#import "CustomView.h"
#implementation CustomView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self loadNib];
}
return self;
}
- (void) loadNib
{
NSArray * subviewArray = [[NSBundle mainBundle] loadNibNamed:#"MyNib" owner:self options:nil];
UIView * mainView = [subviewArray objectAtIndex:0];
[self addSubview:mainView];
}
- (IBAction)close:(id)sender{
[self removeFromSuperview];
}
#end
Now in your ViewController call and add your custom view. You many want this in a IBAction(button click etc).
CGRect frame = CGRectMake(10,10,300, 460);
CustomView *view = [[CustomView alloc] initWithFrame:frame];
[self.view addSubview:view];
When your custom view is added to your main view it will have loaded the nib.
EDIT:To have the x close it. In you customView have a IBACTION and just say
[self removeFromSuperView];
You may want to setup a delegate communicating with your controller to do something on when view on closes etc.
Want a to be able to tap the off custom view to close it, create a UIView put a UITapGestureRecognizer on it that closes your custom view and place it underneath your custom view and cover the whole screen.
Hope this helps,
BooRanger
Related
I followed the tutorial outlined here to load a custom xib in my view controller.
The class of the xib inherits from UIView but also needs a property view:
#interface MYBannerView : UIView
#property (nonatomic, weak) IBOutlet UIView *view;
#end
I find it strange that it needs this, as its like having a view within a view which seems redundant. Is there any particular reason for this?
Edit
I followed this tutorial here which outlines this:
http://www.maytro.com/2014/04/27/building-reusable-views-with-interface-builder-and-auto-layout.html
The author of that tutorial is using the view outlet to load the view from the xib when MYBannerView is initialized programatically
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
NSString *className = NSStringFromClass([self class]);
self.view = [[[NSBundle mainBundle] loadNibNamed:className owner:self options:nil] firstObject];
[self addSubview:self.view];
return self;
}
return nil;
}
Anything created in Interface Builder will not be loaded with a programatic init. loadNibNamed loads the UI from the xib.
If you want to override initWithFrame: to load the UI elements from the xib, your init method would look something like this:
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame]; // initialize your objects
if (self) {
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil]; // load your view from IB
}
return self; // return the view with all of the IB UI loaded
}
No, your UIView subclass doesn't need an outlet to the view to be functional. In fact, using self you have access to the view itself.
What about tutorial: when author added view A (let's call it so) on MYViewController's view, he set view A class to be MYBannerView. Running app won't show anything because MYBannerView xib wasn't loaded and didn't replaced content from view A. So author loads this xib in initWithCoder, set outlet using value returned by loadNibNamed: and adds view loaded from MYBannerView to view A. The process is a little bit messy but it works.
Hello StackOverflow.
I am trying to setup a UIView such that it loads itself from XIB
file in Xcode.
To do this, I went through the following initial steps:
Created empty UIView subclass.
Added a blank XIB file.
Then, I added all the subviews I wanted into the XIB file, and made corresponding IBOutlet Properties inside the UIView Subclass.
I watched this video to show me how to properly connect the outlets and set the files owner. The video instructs me to do the following things:
Do not set the UIView class to your subclass in XIB. Time link
Set the File's Owner to your UIView subclass in XIB:Time Link
Insert a IBOutlet into your UIView class of type UIView so your XIB file can load into that.Time link
Override initWithCoder like (image) if you intend to initialize the custom UIView within another XIB file.
Override initWithFrame like (image) if you intend to initialize the custom UIView programatically within another class file.
Cool, I have done all of these things, and am choosing to initialize my UIView programatically.
See my UIView subclass implementation file:
#import "CXHostsTableViewCellContentView.h"
#implementation CXHostsTableViewCellContentView
#pragma mark Custom Initializers
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[[NSBundle mainBundle]loadNibNamed:#"CXHostsTableViewCellContentView" owner:self options:nil];
[self setBounds:self.view.bounds];
[self addSubview:self.view];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[[NSBundle mainBundle]loadNibNamed:#"CXHostsTableViewCellContentView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
And of course, my header file:
#import <UIKit/UIKit.h>
#import "CXStyleView.h"
#interface CXHostsTableViewCellContentView : UIView
#pragma mark UIView Properties
#property (strong, nonatomic) IBOutlet UIView *view;
#property (nonatomic,weak)IBOutlet UIView *standardView;
#end
I also have an image here of the XIB file's owner and another of the IBOutlet link from the base UIView to the outlet on file's owner.
Right, so everything's looking pretty good, should be no problem running this right?
Nope, whenever I initialize this subview and present it, I get a crash:
CXHostsTableViewCellContentView *scrollContentView = [[CXHostsTableViewCellContentView alloc]init];
I've really got no idea how to solve this, as I'm sure I'm following all of these steps right. I've googled and come across this question which has the same symptoms, but the answer has identical code to what I'm using, and this question with a contradictory reply.
I'm not sure what to do at this point, or what is causing the crash. I know that if I have NO outlets linked at all, it works. But then again, nothing displays either.
I think that You will face Problem When You Allocate Memory to Your scrollContentView object.
so,Try To allocate Memory With Frame.
i.e
Write this in .m file
- (void)myAllocation {
//do your stuff
}
- (id)initWithFrame:(CGRect)aRect {
self = [super initWithFrame:aRect];
if (self) {
[self myAllocation];
}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self myAllocation];
}
return self;
}
...
CXHostsTableViewCellContentView *scrollContentView = [[CXHostsTableViewCellContentView alloc] initWithFrame:CGRectMake(0, 10, 0, 20)];
So, I am using storyboard and I have dragged inside my UIViewController a UIView.
Let's call it customView, and it's class is called SPView. The class is set in the inspector window. Inside the SPView.h there are a number of properties
I have tried the following :
If I drag a label inside the UIView (in the storyboard), the label is shown, but I cannot connect it to one of my outlets in the SPView.h by drag and drop.
If I create a new XIB file, with the label inside, I can do the connections as I like.
Then inside my UIViewController I have tried either of these:
self.customView =[[SPView alloc] initWithFrame:CGRectMake(60, 60, 200, 260)]
self.customView =[[SPView alloc]init];
and inside my SPView, if I use this:
- (id)initWithCoder:(NSCoder *)aDecoder {
NSLog(#"initWitchCoder called");
if ((self = [super initWithCoder:aDecoder])) {
//[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"SPView" owner:self options:nil] objectAtIndex:0]];
[self baseInit];
}
the label is not shown.
If I uncomment the comment, the initWithCoder is called for ever and the app eventually crashes.
What I want is :
to have a custom UIView inside a UIViewController, set either in the storyboard or programmatically (but it will be better if the graphic data are set in storyboard or in a separate .XIB file so as to inspect them more easily).
Can you help me on that?
you cannot drag outlets to custom class uiview class . only its allowed when using xib.
you can drop outlets of that custom view in its parent viewcontroller only.
you can set tags in subviews of your custom view. and can easily access them by using this below code .
lets say you have a subview in your custom view with tag :2
- (id)initWithCoder:(NSCoder *)aDecoder {
NSLog(#"initWitchCoder called");
if ((self = [super initWithCoder:aDecoder])) {
//[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"SPView" owner:self options:nil] objectAtIndex:0]];
UILabel *lbl = (UILabel *)[self viewWithTag:2];
[self baseInit];
}
so you had to set tags to subviews to access them
in your uiviewcontroller you had to drop outlet directly . no need for this
like this it will be initialized automatically
#property (weak, nonatomic) IBOutlet SPView *customView; //right and easy way
X self.customView =[[SPView alloc] initWithFrame:CGRectMake(60, 60, 200, 260)]
X self.customView =[[SPView alloc]init];
You can have following method defined in your UIViewController class and have an XIB created for SPView.
- (SPView*) loadCustomViewFromNib
{
SPView *spView = nil;
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"SPView"
owner:nil
options:nil];
for (id object in array)
{
if ([object isKindOfClass:[SPView class]])
{
spView = (SPView*)object;
break;
}
}
return spView;
}
And have SPView initialized as shown below
self.customView = [self loadCustomViewFromNib];
I am attempting to create a custom subclass of a UIView as follows:
I created a .xib with a UIView that contains a Picker object and Toolbar object, hooked up the Outlets and actions.
CustomPickerView.h
#import <UIKit/UIKit.h>
#interface CustomPickerView : UIView
#property (strong, nonatomic) IBOutlet UIDatePicker* datePicker;
#property (strong, nonatomic) IBOutlet UIBarButtonItem* doneButton;
-(IBAction) buttonDonePush:(id)sender;
#end
CustomPickerView.m
#import "CustomPickerView.h"
#implementation CustomPickerView
-(id) init
{
self=[[[NSBundle mainBundle] loadNibNamed:#"CustomPickerView" owner:self options:nil] objectAtIndex:0];
return self;
}
-(void) buttonDonePush:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"CustomPickerViewDoneButtonPush" object:nil userInfo:[NSDictionary dictionaryWithObject:self.datePicker.date forKey:#"date"]];
}
#end
And finally, in my ViewController I instantiate the object in the viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
self.customPickerView=[[CustomPickerView alloc] init];
self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
self.dateField.inputView=self.customPickerView;
}
When the user taps on the self.dateField, my CustomPickerView pops up nicely in place of the standard keyboard.
The problem is when the user taps the Done button from my CustomPickerView class, the buttonDonePush action does not fire.
This answer can be considered as the iOS companion to a similar solution I offered recently for iOSX:
Interface-Builder: "combine" NSView-class with .xib
Your arrangement is thus:
Mainstoryboard.storyboard
MyViewController.h
MyViewController.m
CustomPickerView.xib
CustomPickerView.h
CustomPickerView.m
You want to use your customPickerView as a subview of MyViewController.view and want to be able to access it's control widgets from the containing context.
In your example you are creating the customPickerView in code, but another useful scenario is to add it to the storyboard in Interface Builder. This solution will work for both scenarios.
In CustomViewPicker.h
declare IBOutlets for your interface elements. You have already done this for your datePicker and doneButton, but you also need an IBOutlet to a UIView which will be the containing view for these items.
#property (strong, nonatomic) IBOutlet UIView* view;
In CustomViewPicker.xib
Set the file's owner class to CustomViewPicker in the Identity Inspector.
Set the top-level view in the xib to the defaul UIView class (NOT CustomViewPicker).
Connect your IBOutlets from the file's owner: view, datePicker, doneButton to their respective IB objects
Connect your IBAction from the file's owner: buttonDonePush to the doneButton IB object
In CustomViewPicker.m:
- (id)initWithFrame:(CGRect)frame
{
//called when initialising in code
self = [super initWithFrame:frame];
if (self) {
[self initialise];
}
return self;
}
- (void)awakeFromNib
{
//called when loading from IB/Storyboard
[self initialise];
}
- (void) initialise
{
NSString* nibName = NSStringFromClass([self class]);
if ([[NSBundle mainBundle] loadNibNamed:nibName
owner:self
options:nil]) {
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
}
}
-(void) buttonDonePush:(id)sender
{
//button push actions
}
If you want to initialise in code (as you have done), your MyViewController would contain something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = CGRectMake(0, 50, 320, 300);
self.customPickerView=[[CustomPickerView alloc] initWithFrame:frame];
self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
self.dateField.inputView=self.customPickerView;
}
[edit removed this redundant line: [self.view addSubview:self.customPickerView];]
Alternatively you can create your CustomPickerView - and set it's frame - directly in the storyboard. Just add a custom view to your MyViewController's storyboard scene, and change it's class to CustomPickerView. Link it to your self.customPickerView IBOutlet.
In this case initWithFrame does not get called, but awakeFromNib is invoked when MyViewController loads it's CustomPickerView subview. Your MyViewController's viewDidLoad would then look like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
self.dateField.inputView=self.customPickerView;
}
If you want to get your button push action out of the customPickerView, you might consider using a delegate, which could be more self-contained than your use of NSNotification (but that issue reaches beyond your original question).
EDIT:
An answer above pointed this out, but in the init method you are setting self, but this happens before self is ever initialized. If you could show the code where you are creating this specific view, it would help a lot. Here's my suggestion.
In your class that is controlling the deployment of this custom view:
//to invoke your view
CustomPickerView *myView;
NSArray *xibContents = [[NSBundle mainBundle]loadNibNamed:#"CustomPickerView" owner:nil options:nil];
for (id xibObject in xibContents) {
if ([xibObject isKindOfClass:[CustomPickerView class]]) {
myView = (CustomPickerView *)xibObject;
break;
}
}
//now *myView is instantiated as your custom picker view
//do what you want here, add to subview, set frame, etc
In the CustomPickerView.m file, remove the init method.
PREVIOUS ANSWER:
You are using NSNotificationCenter in this implementation. When a user touches the done button, an NSNotification is posted. You must explicitly "opt in" and "listen" for these notifications. You do that by registering with the notification center.
In viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedNotification:)
name:#"CustomPickerViewDoneButtonPush"
object:nil];
Then you need to implement the selector you specified up there:
-(void)receivedNotification:(NSNotification *)note {
NSDictionary *obj = [note object];
NSLog(#"%#",obj);
//dismiss the date picker here...
//etc...
}
I have a UIView called baseViewand in that I have initWithFramewhere I add some other views and do some custom stuff. The same view also has a NIB file.
Now I have a UIViewController class named AppController in which I want to add the baseView view to the view of the AppController view so I am doing this:
self.view = baseView; but the problem is that the NIB file does not get loaded. How do I make sure the customized stuff AND the NIB file get´s loaded/run?
You have many options, depending on how your "baseView" class is meant to be used and integrated in to your application. It's not clear just how you intend to use this class -- as the view in a UIViewController subclass, or as a reusable modular component mean to be instantiated multiple times throughout your application, for use in many different view controllers.
If your view is meant to be the only view in a UIViewController subclass, then Phonitive is correct -- bundle it together with the UIViewController subclass .xib file and use the UIViewController's viewDidLoad to do final initialization.
But if you want your View class to be a subcomponent reused multiple times in different view controllers, integrated either via code or via inclusion in a .xib file for another controller, then you need to implement both the initWithFrame: init method, and awakeFromNib, to handle both cases. If your internal initialization always includes some objects from .xib, then in your initWithFrame you'll need to load your .xib manually in order to support "customer" classes that want to create your widget via code. And likewise, if a .xib file contains your object then you'll need to make sure you call any code-required finalization from awakeFromNib.
Here's an example of how to create a UIView subclass component with the UI design in a nib.
MyView.h:
#interface MyView : UIView
{
UIView *view;
UILabel *l;
}
#property (nonatomic, retain) IBOutlet UIView *view;
#property (nonatomic, retain) IBOutlet UILabel *l;
MyView.m:
#import "MyView.h"
#implementation MyView
#synthesize l, view;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code.
//
[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
- (void) awakeFromNib
{
[super awakeFromNib];
// commenters report the next line causes infinite recursion, so removing it
// [[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil];
[self addSubview:self.view];
}
- (void) dealloc
{
[l release];
[view release];
[super dealloc];
}
Here's what the nib file looks like (except that file's owner needs to be changed to MyView class).
be sure to hook up both the view and label outlets to File's Owner. That's it! A template for creating re-usable UIView widgets.
The really neat thing about this structure is that you can place instances of your MyView object in other nib files, just place a UIView at the location/size you want, then change the class in the identity inspector (CMD-4) to MyView, and boom, you've got an instance of your widget in whatever views you want! Just like UIKit objects you can implement delegate protocols so that objects using your widget can be notified of interesting events, and can provide data to display in the widget to customize it.
I found this post after having a problem trying to do this in my app. I was trying to instantiate the view from a NIB in the ViewDidLoad method, but the controls acted as if they were disabled. I struggled with this trying to directly set the userInteractionEnabled property and programmatically set the touch event selector for a button in this view. Nothing worked. I stumbled upon another post and discovered that viewDidLoad was probably too soon to be loading this NIB. I moved the load to the ViewWillAppear method and everything worked. Hope this helps someone else struggling with this. The main response was great and works well for me now that I have it being called from the proper place.
if you want to use a NIB, it's better for your UIView to be linked with a UIViewController, in this case you can use
UIViewController *vc=[[UIViewController alloc] initWithNibName:#"YourNIBWihtOUTEXTENSION" bundle:nil]
[self.view addSubView:vc.view ];
becareful of memory leaks, you have to release vc
If you have a custom UIView with a xib file.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
id mainView;
if (self)
{
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"HomeAllAdsView" owner:self options:nil];
mainView = [subviewArray objectAtIndex:0];
}
return mainView;
}
- (void) awakeFromNib
{
[super awakeFromNib];
}
This post helped me Building Reusable Views With Interface Builder and Auto Layout. The trick had to do with setting the IBOutlets to the FileOwner and then adding the content view to itself after loading the nib