I have successfully made a project in swift where I press buttons in my viewController to load other viewControllers or xib files into a container. Just to give you an idea:
It works great, but I'm having a difficult time translating it to objective-c which is where the code is actually needed. This is what the swift code looks like when pressing a button:
let sub3 = UINib(nibName: "thirdXib", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
containerOutlet.addSubview(sub3)
NSLayoutConstraint.activate([
sub3.leadingAnchor.constraint(equalTo: containerOutlet.leadingAnchor),
sub3.trailingAnchor.constraint(equalTo: containerOutlet.trailingAnchor),
sub3.topAnchor.constraint(equalTo: containerOutlet.topAnchor),
sub3.bottomAnchor.constraint(equalTo: containerOutlet.bottomAnchor)
])
Now, I would like all that code to be in objective-c instead. In objective-c I have done the first part, which I assume is correct:
UINib *nib = [UINib nibWithNibName:#"SecondView" bundle:nil];
[nib instantiateWithOwner:self options:nil];
[containerOutlet addSubview:((UIView*)nib)];
But I'm having problem with the last part, NSLayoutConstraint activateConstraints
[NSLayoutConstraint activateConstraints:#[
[nib.lead],
[nib.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
]
];
The compiler says that property lead not found on object of type UIBib and same on the code just below. I have tried a variation of these, but don't get it right. How do I set trailing, leading, bottom and top constraints on my xib? Do I need to add #import SecondView.xib" in the.h` file? by the way?
You can try
UINib *nib = [UINib nibWithNibName:#"SecondView" bundle:nil];
UIView *sub3 = [nib instantiateWithOwner:self options:nil][0];
[containerOutlet addSubview:sub3];
[NSLayoutConstraint activateConstraints:#[
[sub3.leadingAnchor constraintEqualToAnchor:scontainerOutlet.leadingAnchor],
[sub3.trailingAnchor constraintEqualToAnchor:containerOutlet.trailingAnchor],
[sub3.topAnchor constraintEqualToAnchor:containerOutlet.topAnchor],
[sub3.bottomAnchor constraintEqualToAnchor:containerOutlet.bottomAnchor]
]];
Related
I am working on a project for iOS 7.0+ with a storyboard, using Size Classes with AutoLayout and I'm using a UIView subclass backed by a xib file of the same name.
What I'am trying to do is I'am instantiating a UIView from xib programmatically and adding it to a ViewController from a Storyboard. This ViewController has AutoLayout up and running but the UIView I am adding doesn't respect the frame of the ViewController.
I'm instantiating my UIView subclass like this:
tabBarView = [[SHDTabBarView alloc] initWithFrame:CGRectMake(0, self.view.height-50, self.view.width, 50)];
[self.view addSubview:tabBarView];
And inside the subclass I'm using a set up of creating a UIView IBOutlet called container to instantiate it form code like this:
-(id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self == nil) return nil;
[self initalizeSubviews];
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self == nil) return nil;
[self initalizeSubviews];
return self;
}
-(void)initalizeSubviews{
NSString *nibName = NSStringFromClass([self class]);
UINib *nib = [UINib nibWithNibName:nibName bundle:nil];
[nib instantiateWithOwner:self options:nil];
//Add the view loaded from the nib into self.
[self addSubview:self.container];
}
This is how my xib looks in the Interface Builder (notice the width of the canvas is 320 px):
And that's how it looks on the iPhone 6 (notice how it's getting cut off from the right side):
I've tried to use a multitude of solutions, including doing it all in code with an open-source solution PureLayout, using a manual constraint set up, etc.
None of my findings seem to work right. Ideally, I want to set up everything in Interface Builder, then just add the view to the superview of the ViewController with according frame and let AutoLayout do its magic.
How should I approach this task? Any advices are more than welcome.
Try to set the frame of your subview in the viewDidLayoutSubviews(). Looks like you init your subview before view fully layouted
I want to display the contents of a .xib file when a button is pressed in my app. It would be the equivalent of the following in android:
Intent intent = new Intent(myActivity.this,classiwanttogoto.class);
startActivity(intent);
Is there something equivalent to that in Cocoa Touch? I know that it is very easy with storyboards, and if it comes to that I will use it, but I would like iOS 4 support.
You initialize UIViewControllers like so:
MyViewController *viewController = [MyViewController alloc] initWithNibName:#"MyNibName" bundle:nil];
And then you use it.
Or you can initialize a view from a nib:
UIView *myView = [[[NSBundle mainBundle] loadNibNamed:#"MyViewName" owner:self options:nil] objectAtIndex:0];
I have a UIViewController (Main VC) into which another UIView is loaded as subview when a button is tapped on MainViewController. Actually I load a map view as subview in the main view controller. For that purpose I need to pass the coordinate from MainViewController to the subview (map view) to create the annotation there & then loaded inside the MainViewController.
In MainViewController the following method loads the subview correctly:
-(IBAction)showUserLocation{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"UserCurrentLocationView" owner:self options:nil];
UIView *currentLocationView = [nib objectAtIndex:0];
currentLocationView.frame = CGRectMake(8, 10, currentLocationView.frame.size.width, currentLocationView.frame.size.height);
[thirdPortion addSubview:currentLocationView]; // thirdPortion is a View Outlet in the Main VC wh
}
Here I want to pass a coordinate (lat/lon) to the UserCurrentLocationView 's class so that it can prepare the map and I can see the pointed map in the MainViewController when showUserLocation method is called by a button.
What is the way to set the value of a property that stays on the UIView (Subview) from the MainViewController.
Thanks in advance!
You have to subclass the UIView (I will call it YourView) and add a two properties for long and lat. Then put it as the class for your .xib - file named UserCurrentLocationView.
Then you do the following to set the variables.
-(IBAction)showUserLocation{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"UserCurrentLocationView" owner:self options:nil];
YourView *currentLocationView = (YourView *)[nib objectAtIndex:0];
currentLocationView.lon = self.fooValue;
currentLocationView.lat = self.fooValue2;
currentLocationView.frame = CGRectMake(8, 10, currentLocationView.frame.size.width, currentLocationView.frame.size.height);
[thirdPortion addSubview:currentLocationView]; // thirdPortion is a View Outlet in the Main VC wh
}
Im trying to add a UIView to the UIView that is currently showing.
This is the code I've come up with:
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UINavigationController *nav = window.rootViewController;
UIViewController *viewController = [[nav viewControllers]lastObject];
NSLog(#"La clase: %#", [viewController class]);
[viewController.view addSubview:self.infoMsg];
The problem is that I dont see that UIView, the value of the variable viewController is correct, but I don't see the view added on that view...
Thanks
[EDIT]
I just checked and If for example instead of add as a subview infoMsg which is a UIView that I have syntesized, and I add a UIView that I create just before adding it adds correctly why is that? why can't I add an attribute of my object?
You have to still create the view before adding it, no matter if it's a property or just a local variable. I don't see where you initialize self.infoMsg. It's probably nil.
Try this:
NSLog(#"%#", self.infoMsg == nil ? #"It's nil" : #"It's not nil");
If it's nil, that that's your problem.
I need to create several similar views
In a easy way,I create some views in xib(each full screen)
And I have a view controller to use this xib's views,code like this:
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"MyXibName" owner:nil options:nil];
[self.view addSubview:[views objectAtIndex:aIndex]];
At this moment,view shows alright.
Now,there's some buttons in those views,so I connect a outlet for each view
bad thing happened
app crashed due to
uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x969db50> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key
Analyse:
Although my xib file's "File Owner" has been set,but there's no connection between xib and the only view controller.
How could I get the pointer of a view's button?
You can do it like this:
NSNib* aNib = [[NSNib alloc] initWithNibNamed:#"MyGreatNib" bundle:nil];
NSArray* topLevelObjs = nil;
for (SomeClass *obj in myOwnerObjects) {
topLevelObjs = nil;
if (![aNib instantiateNibWithOwner:obj topLevelObjects:&topLevelObjs])
{
NSLog(#"Warning! Could not load nib file.\n");
return;
}
for (id topLevelObj in topLevelObjs) {
if ([topLevelObj isKindOfClass:[NSView class]]) {
NSView *otView = (NSView *)topLevelObj;
// set frame...
[self addSubview:otView];
}
}
}
Oops...
I just found something.
UINib* xib = [UINib nibWithNibName:#"MyXibName" bundle:nil];
UIView* view = [[xib instantiateWithOwner:self options:nil] lastObject];
It works!
You can design xib as per your need by defining class UIView
Code in .m file:
NSArray* objects = [[NSBundle mainBundle] loadNibNamed:#"Interface" owner:nil options:nil];
UIView* mainView = [objects objectAtIndex:0];
for (UIView* view in [mainView subviews]) {
if([view isKindOfClass:[UILabel class]])
{
UILabel* label = (UILabel*)view;
//....As You Wish...
}
}
Default implementation of -loadView creates the view or loads NIB. As far as I know, there is no way to know the final size of the view at time of creation in -loadView. So the default view size is set to [[UIScreen mainScreen] bounds]. This is because it may be difficult to work work with zero frame view in -viewDidLoad and other methods.
Your one-line implementation may look like this:
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
You don't need to set the autoresizing mask, because you don't know in what context the view will be displayed. The caller is responsible to set you correct frame, autoresizing mask and similar external attributes (I call them like this).
Imagine this in a UINavigationController method:
// we are pushing new VC, view is accessed for the first time
pushedVC.view.frame = CGRectMake(...);
It is setting the correct frame, but your -loadView is called just before that -setFrame:. So during -viewDidLoad you have temporary non-zero frame, just to be able to setup subviews and internal autoresizing. After this, the correct frame is set to you and in -viewWillAppear: you have final frame.