I am having a NSView let call this Detail View in my main view controller in which all the auto layout constraints will be added in dependent with the main view. I will be adding a subview lets call this sub detail to this Detail View based on user input. This sub detail view contains lot of view for which constraints are added in accordance with the sub detail view. While adding the sub detail to Detail View as sub view I am setting the frame by getting the frame of Detail View and setting x = 0 and y = 0;. My problem is that when a user maximise the window and user select and I am adding the sub detail view to Detail View the size of sub detail subview remains the same but sub detail view get auto resized as per required. Could any one guide me what i am doing wrong. Below i am sharing you the code where in which i am adding the subview and output view in the link
I don't want the blank blue space.
NSRect f = detailView.frame;
f.origin.x = 0;
f.origin.y = 0;
ConfigLogin *subDetail = [[ConfigLogin alloc] initWithFrame:f];
[subDetail setWantsLayer:YES];
[subDetail setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
[subDetail setTranslatesAutoresizingMaskIntoConstraints:YES];
subDetail.layer.backgroundColor = [NSColor blueColor].CGColor;
subDetail.frame = f;
[detailView addSubview:detailView];
I could find the answer as while adding the subview we are not adding the constraints to make the view fit to the super view.
+(void) fitSubViewToSuperView:(NSView *) subview superView:(NSView *) superView
{
NSLayoutConstraint *width = [NSLayoutConstraint
constraintWithItem:subview
attribute:NSLayoutAttributeWidth
relatedBy:0
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
NSLayoutConstraint *height = [NSLayoutConstraint
constraintWithItem:subview
attribute:NSLayoutAttributeHeight
relatedBy:0
toItem:superView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
NSLayoutConstraint *top = [NSLayoutConstraint
constraintWithItem:subview
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.f];
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:subview
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
[superView addConstraint:width];
[superView addConstraint:height];
[superView addConstraint:top];
[superView addConstraint:leading];
}
Related
I am on Xcode 8.3.3, OSX not iOS.
I have a customView I use as container to replace other views inside it.
The dark blue box on the right represents the container:
The constraints of the container are set in IB as follows where "scrollView" is the tables scroll view left of it:
This enables vertical scaling (scrollView is allowed to scale vertically) which is the desired behaviour:
Now I add a subview to the container with this code:
NSStoryboard *storyBoard = [NSStoryboard storyboardWithName:#"Main" bundle:nil];
_previewViewController = [storyBoard instantiateControllerWithIdentifier:#"showSHPreviewViewController"];
CGRect newFrame = CGRectMake(0, 0,CGRectGetWidth(_previewViewController.view.bounds),CGRectGetHeight(_previewViewController.view.bounds));
_previewViewController.view.frame = newFrame;
[self.previewContainer addSubview:_previewViewController.view];
This works as expected:
My Problem is, I want the subview to be stretched so it fits the whole height of its container. Therefore I have to set NSLayoutConstraints programmatically. But i don't get the logic.... Whatever I try leads to a behaviour where neither the scroll view nor the container can scale vertically at all.
This was my last try before I wrote this post:
[self.previewContainer addConstraint:[NSLayoutConstraint
constraintWithItem:_previewViewController.view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.previewContainer
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0]];
[self.previewContainer addConstraint:[NSLayoutConstraint constraintWithItem:_previewViewController.view
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.previewContainer
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0]];
[self.previewContainer addConstraint:[NSLayoutConstraint constraintWithItem:_previewViewController.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.previewContainer
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
I can confirm that the content of the added subview is setup correctly and resizeable (no "height-lock").
I'm currently attempting to add a UIIMageView on top of a class.
Without constraints, I can add an object such as an UIImageView without any hindrance: [self addSubview:myImage];.
However, when I add [myImage setTranslatesAutoresizingMaskIntoConstraints: NO]; along with the needed constraints, the image is added to the UIViewController versus the class.
(Right now, the sizeX/Y is a separate algorithm to set the image width and height and won't be needed assuming constraints will work)
1) Why is that?
2) How can add a UIImageView with constraints?
Here's the code:
UIImageView *myImage = [[UIImageView alloc] init];
//AutoResize...
myImage.frame = CGRectMake(0, 0, sizeX, sizeY);
myImage.center = CGPointMake(placementX, placementY);
myImage.image = [UIImage imageNamed:#"customImage"];
[self addSubview:myImage];
// Width constraint
[self addConstraint:[NSLayoutConstraint constraintWithItem:myImage
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0]];
// Height constraint
[self addConstraint:[NSLayoutConstraint constraintWithItem:myImage
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0]];
Thanks!
I'm currently attempting to add a UIMageView on top of a class...
...the image is added to the view controller versus the class.
Neither of these statements make sense to me, but...
Looking at your constraint code, you set constraints for the width and height of the image view, but that is not enough to unambiguously position the image view. You need to add 2 constraints: for the vertical and horizontal position of the image view. For example if you want the image view centered in its superview:
[self addConstraint:[NSLayoutConstraint constraintWithItem:myImage
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:myImage
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0]];
I'm trying to fill a UIView with a UIImageView using auto layout. I've tried several thing, but the most obvious, equalSize with parent view only works when I set the correct size in "Simulated metric". If I let Freeform (the point of autolayout isn't it ?) I get messed up.
I'm testing on an iPhone 4S and a 6 plus.
Thanks for any leading tracks.
EDIT FOR #mittens
I've seen your edit. I still can get it working. As you see I have 4 margin constraints, the same as in your code (I did not need the rest because I only use the main UIView).
Anyway, when I change the size on xcode, the layout is perfect, when I send it to my 4S, I only get Top and left margins.
I'd double check the constraints on the UIView you're trying to fill with the UIImageView to make sure it is filling up its parent view as it should be when the storyboard/xib is set to freeform. Also if you're adding/creating the views programmatically double check that the views 'translatesAutoresizingMaskIntoConstraintsis set toNO`. That always trips me up.
I made a super quick view and added some constraints to both a view inside the View Controllers view and an Image view to show one way to do it -- hopefully it helps at least a little
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.backdropView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.backdropView.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.5];
self.backdropView.translatesAutoresizingMaskIntoConstraints = NO; // Make sure this is set to NO if the view is being added programmatically
[self.view addSubview:self.backdropView]; // Always add the view into the hierarchy _before_ constraints are added (again, if creating & adding programmatically)
NSLayoutConstraint *backdropViewWidth = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0];
NSLayoutConstraint *backdropViewHeight = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeHeight multiplier:0.5 constant:0];
NSLayoutConstraint *backdropViewCenterX = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
NSLayoutConstraint *backdropViewCenterY = [NSLayoutConstraint constraintWithItem:self.backdropView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.backdropView.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
[self.backdropView.superview addConstraints:#[backdropViewWidth, backdropViewHeight, backdropViewCenterY, backdropViewCenterX]];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.imageView.translatesAutoresizingMaskIntoConstraints = NO;
self.imageView.backgroundColor = [UIColor colorWithRed:1 green:0 blue:1 alpha:0.5];
[self.backdropView addSubview:self.imageView];
NSLayoutConstraint *imageViewTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeTop multiplier:1 constant:8];
NSLayoutConstraint *imageViewLeft = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeLeft multiplier:1 constant:8];
NSLayoutConstraint *imageViewRight = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeRight multiplier:1 constant:-8];
NSLayoutConstraint *imageViewBottom = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.imageView.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:-8];
[self.imageView.superview addConstraints:#[imageViewTop, imageViewLeft, imageViewRight, imageViewBottom]];
[self.view layoutIfNeeded];
}
That produces and
Again, hopefully this helps.
EDIT: how to add them in storyboard
Note on photo 3, I select the view I want to constrain and then shift select the view I want to constraint it to. So I selected the inside UIView (because it width/height will be constrained to the parent view) then shift selected its parent view (the view it is nested inside of) to enable those options of Equal Width & Equal Height
Add constraints to UIImageView nested inside the UIView
Center UIView inside its parent view
Add width/height constraints equal to parent -- Note: I select the view I want to constrain and then shift select the view I want to constraint it to. So I selected the inside UIView (because it width/height will be constrained to the parent view) then shift selected its parent view (the view it is nested inside of) to enable those options of Equal Width & Equal Height
Change multiplier in constraint to be whatever you want, 0.5 in this case
Celebrate
i'm not sure but try this in your imageview.
[imgView clipToBounds:YES];
I hope it's work for you
I want a custom UIView in my UINavigationBar between a left and a right BarButtonItem but as wide as possible. For this reason I added a UIView in IB to the NavigationBar. With autolayout disabled everything works as expected with the autoresizing masks.
But in my storyboard with autolayout enabled I just cann't get it to work. It doesn't look like I can set any constraints in IB for the titleView. If I rotate my device to landscape mode, the UIView has still the same width.
What do I have to do so that the titleView fills the space between my UIBarButtonItems with autolayout enabled?
Thank you for any help
Linard
I solved the issue as following in my code:
- (void)willAnimateRotationToInterfaceOrientation:(__unused UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
CGSize navigationBarSize = self.navigationController.navigationBar.frame.size;
UIView *titleView = self.navigationItem.titleView;
CGRect titleViewFrame = titleView.frame;
titleViewFrame.size = navigationBarSize;
self.navigationItem.titleView.frame = titleViewFrame;
}
I haven't found another solution (with automatic resizing), but I'm open for new and/or better solutions
Linard
You can add constraints in code.
In viewDidLoad, you can do something like this:
UIView *titleView = [[UIView alloc] initWithFrame:CGRectZero];
self.navigationItem.titleView = titleView;
UIView *titleViewSuperview = titleView.superview;
titleView.translatesAutoresizingMaskIntoConstraints = NO;
[titleViewSuperview addConstraint:[NSLayoutConstraint constraintWithItem:titleView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:titleViewSuperview attribute:NSLayoutAttributeLeading multiplier:1 constant:0]]; // leading
[titleViewSuperview addConstraint:[NSLayoutConstraint constraintWithItem:titleView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleViewSuperview attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; // top
[titleViewSuperview addConstraint:[NSLayoutConstraint constraintWithItem:titleViewSuperview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]]; // width
[titleViewSuperview addConstraint:[NSLayoutConstraint constraintWithItem:titleViewSuperview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; // height
I'm fairly new to iOS development but have reached the point where I want to create my own composite UIView as a custom UIButton. I would like to layout a UILabel and 2x UIImageViews as follows;
But I would also like to anchor the controls (subviews) in such a way that as the label expands, due to translations say, the view automatically handles the extra real estate. For example;
Ideally -
the right hand side UIView is anchored to the right; and remains a fixed width/hight (right aligned).
the label and bottom image divide the remaining left hand space
the label is vertically centered in the top half of the upper remaining space
the bottom image remains centered (both vertically and horizontally) in the lower remaining space
if the label is wider than the bottom image then the view should expand
I'm happy to construct this in pure code if required. I used a XIB in the above images to play with attributes and to visualize my question.
I'm from a C#/XAML background so I would typically use grid layouts with fixed/auto/* columns and rows but I'm guessing I need to use something like NSLayoutConstraints here - unfortunately I don't know where to start or how to search for the solution. Any help appreciated!
in your UIButton
(code not tested)
//put the code below in your button's init method
UILabel *label = [[UILabel alloc] init];
UIImageView *bottomImageView = [[UIImageView alloc] init];
UIImageView *rightImageView = [[UIImageView alloc] init];
// we define our own contraints,
// we don't want the system to fall-back on UIView's autoresizingMask property (pre-iOS 6)
self.translatesAutoresizingMaskIntoConstraints = NO;
label.translatesAutoresizingMaskIntoConstraints = NO;
bottomImageView.translatesAutoresizingMaskIntoConstraints = NO;
rightImageView.translatesAutoresizingMaskIntoConstraints = NO;
//fixed sizes => SET THESE as you want
CGFloat labelHeight, bottomWidth, rightImageWidth;
// 1 - Label constraints :
// labelWidth = 1 *self.width - rightImageWidth
NSLayoutConstraint *labelWidth = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeWidth
multiplier:1
constant:(- rightImageWidth)];
// label must be at the top :
NSLayoutConstraint *labelTop = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
//label must be on the left border
NSLayoutConstraint *labelLeft = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeft
multiplier:1
constant:0];
//label must be of 1/2 height
NSLayoutConstraint *labelHeight = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0];
[self addSubview:label];
[self addConstraints:#[labelWidth, labelTop, labelLeft, labelHeight]];
//2 - botom view
// width constant
NSLayoutContraint *bottomWidth = [NSLayoutConstraint constraintWithItem:bottomImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0
constant:bottomWidth];
// same height constraint as label
NSLayoutConstraint *bottomHeight = [NSLayoutConstraint constraintWithItem:bottomImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0];
// sticks at container's bottom (pun intended)
NSLayoutConstraint *bottomBottom = [NSLayoutConstraint constraintWithItem:bottomImageView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1
constant:0];
//we have height, width, y contraints, just x remains
// NOTE : this one is between bottom view and label
NSLayoutConstraint *bottomCenteredXAsLabel = [NSLayoutConstraint constraintWithItem:bottomImageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:label
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
[self addSubview:bottomImageView];
[self addConstraints:#[bottomWidth, bottomHeight, bottomBottom, bottomCenteredXAsLabel]];
// 3 - last one !
NSLayoutConstraint *rightAligned = [NSLayoutConstraint constraintWithItem:rightImageView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeRight
multiplier:1
constant:0];
//right height
NSLayoutConstraint *rightHeight = [NSLayoutConstraint constraintWithItem:rightImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0];
//constant width...
NSLayoutConstraint *rightWidth = [NSLayoutConstraint constraintWithItem:rightImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0
constant:rightImageWidth];
//width, height, x constraints...
//we still need one on y, let's say it sticks at the top
NSLayoutConstraint *rightTop = [NSLayoutConstraint constraintWithItem:rightImageView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:0];
[self addSubview:rightImageView];
[self addConstraints:#[rightAligned, rightHeight, rightWidth, rightTop]];
Et voilĂ !
The method is always the same : you need at least 4 constraints on each view, setting width, height, x, and y (CGRect 4 dimensions).
Think of a constraint as a relation :
item1.layoutAttribute1 >= a*item2.layoutAttribute2 + b
to translate in this form
[NSLayoutConstraint constraintWithItem:item1
attribute:layoutAttribute1
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:item2
attribute:layoutAttribute2
multiplier:a
constant:b];
Note that using visual format, you might express all that with less code. (but I've not played with it yet).