how content inset affects layout - ios

While working with UIScrollView, I noticed some weird behavior about auto layout and content inset; take the following code for example:
- (void) loadView
{
UIScrollView * scroller = [[UIScrollView alloc] init];
scroller.backgroundColor = [UIColor orangeColor];
UILabel * label = [[UILabel alloc] init];
label.backgroundColor = [UIColor blueColor];
label.translatesAutoresizingMaskIntoConstraints = NO;
[scroller addSubview:label];
[scroller addConstraint: [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:scroller attribute:NSLayoutAttributeLeft multiplier:1.0 constant:40]];
[scroller addConstraint: [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scroller attribute:NSLayoutAttributeTop multiplier:1.0 constant:20]];
[scroller addConstraint: [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:240]];
[scroller addConstraint: [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:44]];
self.view = scroller;
scroller.contentInset = UIEdgeInsetsMake(44, 0, 0, 0); //this is the game changer
}
Without the last line that changes the content inset, the UILabel is at (40, 20) as expected. When altering the content inset, the label moved to (40, 108), instead of (40, 64); the top content inset is somehow doubled.
If the UILabel is created with set frame and without those constraints as:
- (void) loadView
{
UIScrollView * scroller = [[UIScrollView alloc] init];
scroller.backgroundColor = [UIColor orangeColor];
CGRect frame = CGRectMake(40, 20, 240, 44);
UILabel * label = [[UILabel alloc] initWithFrame:frame];
label.backgroundColor = [UIColor blueColor];
[scroller addSubview:label];
self.view = scroller;
scroller.contentInset = UIEdgeInsetsMake(44, 0, 0, 0);
}
Then it behave as expected (40, 20) and (40, 64) depending on the content inset.
I checked with the documents and tried flipping some switches, but still can't figure out why.
BTW, that was the result from the IOS(6) simulator, I did not try it on device yet.
P.S.
Things appear as expected on simulator with IOS7, except the difference of the new status bar behavior.

Related

Center SubViews in ParentView in Objective-C

I have the following code:
UIView *parentView = [[UIView alloc] init];
parentView.frame = CGRectMake(0, 0, 100, 100);
parentView.center = self.view.center;
parentView.backgroundColor = [UIColor greenColor];
UIView *subView = [[UIView alloc] init];
subView.backgroundColor = [UIColor redColor];
subView.frame = CGRectMake(0, 0, 50, 50);
subView.center = parentView.center;
[parentView addSubview:subView];
[self.view addSubview:parentView];
Which produces the following result:
Why is the red view not centered in the green view since they have the same center?
The Apple UIView documentation states for the center property:
The center is specified within the coordinate system of its superview and is measured in points. Setting this property changes the values of the frame properties accordingly.
That means the parentView center will be relative to its superview (the white background view by the looks of your screenshot).
To get the desired result you need to do something like this:
subview.center = CGPointMake(CGRectGetMidX(parentView.bounds),
CGRectGetMidY(parentView.bounds));
But you should really be using autolayout for this type of thing.
You are setting the green view to be the center of it's superview, but you are setting the red view to be in the center of it's superview's superview...
The way to fix that with the smallest amount of code change would be to change the red view's superview.
[self.view addSubview:parentView];
[self.view addSubview:subView];
EDIT: To explain a little further what is going on. Say when you set the center of your green view it gets set to (500,500). That's inside it's superview, so it gets set to the middle of the screen. Then you set your red view's center to the same value as the green view's center, (500,500). But it's parent that it is relative to is the red view, so it gets placed (500,500) from the origin point of the green view. It gets placed near the bottom right of the screen.
You are Doing Like this
UIView *parentView = [[UIView alloc] init];
parentView.frame = CGRectMake(0, 0, 100, 100);
parentView.center = self.view.center;
parentView.backgroundColor = [UIColor greenColor];
UIView *subView = [[UIView alloc] init];
subView.backgroundColor = [UIColor redColor];
CGFloat SubviewX = (parentView.frame.size.width - 50)/2;
CGFloat SubviewY = (parentView.frame.size.height - 50)/2;
subView.frame = CGRectMake(SubviewX, SubviewY, 50, 50);
[parentView addSubview:subView];
[self.view addSubview:parentView];
The best way to center a view, and maintain it that way even if the view changes its view frame is using constraints:
UIView *parentView = [[UIView alloc] init];
parentView.translatesAutoresizingMaskIntoConstraints = NO;
// You might want to add constraints for the view's size
parentView.frame = CGRectMake(0, 0, 100, 100);
parentView.backgroundColor = [UIColor greenColor];
[self.view addSubview:parentView];
NSContraint *xContraint = [NSLayoutConstraint constraintWithItem:parentView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
[self.view addConstraint:xContraint];
NSContraint *yContraint = [NSLayoutConstraint constraintWithItem:parentView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0];
[self.view addConstraint:yContraint];
UIView *subView = [[UIView alloc] init];
subView.translatesAutoresizingMaskIntoConstraints = NO;
// You might want to add constraints for the view's size
subView.frame = CGRectMake(0, 0, 50, 50);
subView.backgroundColor = [UIColor redColor];
[parentView addSubview:subView];
NSContraint *xSubContraint = [NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
[parentView addConstraint:xSubContraint];
NSContraint *ySubContraint = [NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0];
[parentView addConstraint:ySubContraint];

UILabel is not centered in my UIView

I'm adding a UILabel to a UIView on initialization and the label will not center itself. I've tried centering it is layoutSubviews and adding constraints programmatically with no luck. When it appears it is about 200 pixels to the left of the center. Here is my code. Thanks in advance.
- (instancetype)initWithTitle:(NSString *)title andBody:(NSString *)body Andwidth:(CGFloat)width {
self = [super initWithFrame:CGRectMake(0, 0, width, 60)];
if (self) {
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 60)];
containerView.backgroundColor = [UIColor orangeColor];
[self addSubview:containerView];
self.winningLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0, 300, 40)];
self.winningLabel.textColor = [UIColor whiteColor];
self.winningLabel.font = [UIFont fontWithName:#"Avenir" size:30];
self.winningLabel.backgroundColor = [UIColor clearColor];
self.winningLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.winningLabel.numberOfLines = 2;
self.winningLabel.text = #"YOU WIN";
self.winningLabel.hidden = YES;
[containerView addSubview:self.winningLabel];
NSLayoutConstraint *xCenterConstraint = [NSLayoutConstraint constraintWithItem:self.winningLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
[self addConstraint:xCenterConstraint];
NSLayoutConstraint *yCenterConstraint = [NSLayoutConstraint constraintWithItem:self.winningLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0];
[self addConstraint:yCenterConstraint];
}
return self;
}
- (void)layoutSubviews {
[self.winningLabel setCenter:self.center];
}
I think you forget the text alignment. By default the text in a label is aligned to the left. If you want it to be in the center, you should specify it explicitly.
self.winningLabel.textAlignment = NSTextAlignmentCenter;

how to set subview of UIScrollView using autolayout

i am trying to implement Horizontal scrollview with ten views.
its working fine in portrait mode but i want same scenario in landscape too.
can anyone help me by which constraint i can achieve this?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title=#"Demo.....";
self.myScrollView.pagingEnabled = YES;
NSInteger numberOfViews = 10;
for (int i = 0; i < numberOfViews; i++) {
CGFloat myOrigin = i * self.view.frame.size.width;
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(myOrigin, 0, self.view.frame.size.width, self.view.frame.size.height)];
myView.backgroundColor = [UIColor purpleColor];
CGRect myFrame = CGRectMake(10.0f, 70.0f, 200.0f, 25.0f);
UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
myLabel.translatesAutoresizingMaskIntoConstraints = NO;
myLabel.text = [NSString stringWithFormat:#"This is page number %d", i];
myLabel.font = [UIFont boldSystemFontOfSize:16.0f];
myLabel.textAlignment = NSTextAlignmentLeft;
[myView addSubview:myLabel];
//set the scroll view delegate to self so that we can listen for changes
self.myScrollView.delegate = self;
//add the subview to the scroll view
[self.myScrollView addSubview:myView];
NSLayoutConstraint *constraintLeft = [NSLayoutConstraint constraintWithItem:myView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.myScrollView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0];
// 0px to the right of the UIScrollView
NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:myView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.myScrollView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0];
[self.myScrollView addConstraint:constraintLeft];
[self.myScrollView addConstraint:constraintRight];
}
//set the content size of the scroll view, we keep the height same so it will only
//scroll horizontally
self.myScrollView.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews,
self.view.frame.size.height);
//we set the origin to the 3rd page
CGPoint scrollPoint = CGPointMake(self.view.frame.size.width * 2, 0);
//change the scroll view offset the the 3rd page so it will start from there
[myScrollView setContentOffset:scrollPoint animated:YES];
[self.view addSubview:self.myScrollView];
}
in my above code,
ten view is completely added into scrollview and working fine in portrait mode but when i change the orientation to horizontal it will not resize and not scrolled.
You need to tie subviews width constraint equal to scrollView width
for (UIView *subView in subViews)
{
NSLayoutConstraint *constraintEqualWidth = [NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.myScrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0.0];
[subView addConstraint:constraintEqualWidth];
}

NSLayoutConstraints to UITextField - Error

I have a simple setup with 3 views:
view, which has 1 subview contentView, which has 1 subview emailField (a UITextField).
emailfField is not aligning in centerY correctly. I got is this error:
"<NSLayoutConstraint:0x9e7d500 UIView:0x9e85c30.centerY == UITextField:0x9e4dbd0.centerY>",
"<NSLayoutConstraint:0x9e7cc00 UIView:0x9e85530.top == UIView:0x9e85c30.top>",
"<NSAutoresizingMaskLayoutConstraint:0x9e7f950 h=--& v=--& UITextField:0x9e4dbd0.midY == + 282.5>",
"<NSAutoresizingMaskLayoutConstraint:0x9e81e90 h=--& v=--& UIView:0x9e85c30.midY == + 240>")
My .m file:
- (void)viewDidLoad {
[super viewDidLoad];
[self initContentView];
[self initFirstView];
[self addConstraints];}
- (void)addConstraints {
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
//First View
//Email Field
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.emailField
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];}
- (void)initContentView {
self.view.backgroundColor = [UIColor colorWithRed:239.0f/255.0f green:239.0f/255.0f blue:239.0f/255.0f alpha:1.0];
self.contentView = [[UIView alloc] initWithFrame:self.view.frame];
self.contentView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.contentView];
int frameHorizontalCenter = self.contentView.frame.size.width/2;
self.funView = [[UIImageView alloc] initWithFrame:CGRectMake(frameHorizontalCenter-50, 100, 100, 100)];
self.funView.backgroundColor = [UIColor clearColor];
self.funView.image = [UIImage imageNamed:#"dog1"];
[self.contentView addSubview:self.funView];
self.descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(frameHorizontalCenter - 140, self.funView.frame.origin.y + self.funView.frame.size.height, 280, 60)];
self.descriptionLabel.font = [UIFont systemFontOfSize:14];
self.descriptionLabel.textColor = [UIColor colorWithRed:63.0f/255.0f green:63.0f/255.0f blue:63.0f/255.0f alpha:1.0];
self.descriptionLabel.backgroundColor = [UIColor clearColor];
self.descriptionLabel.highlightedTextColor = [UIColor whiteColor];
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.numberOfLines = 2;
self.descriptionLabel.adjustsFontSizeToFitWidth = YES;
self.descriptionLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView addSubview:self.descriptionLabel];
self.emailField = [[UITextField alloc] initWithFrame:CGRectMake(frameHorizontalCenter -140, self.descriptionLabel.frame.origin.y + self.descriptionLabel.frame.size.height, 280, 45)];
self.emailField.borderStyle = UITextBorderStyleNone;
self.emailField.textColor = [UIColor colorWithRed:63.0f/255.0f green:63.0f/255.0f blue:63.0f/255.0f alpha:1.0];
self.emailField.backgroundColor = [UIColor whiteColor];
self.emailField.placeholder = #"Epasts";
[self.contentView addSubview:self.emailField];}
I really don't understand what's wrong. Aren't constraints set correctly?
Use setTranslatesAutoresizingMaskIntoConstraints: to turn off conversion of autoresizing masks to constraints on contentView and emailField. Add additional constraints to emailField to specify the x position, width and height that it should use.

How to add label programmatically and position it with auto layout programmatically

I'm trying add a label to a UIScrollView. I'm adding a top constraint and a leading constraint.
The label is not appearing.
Here is my code.
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
self.label.translatesAutoresizingMaskIntoConstraints = NO;
self.label.backgroundColor = [UIColor clearColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.textColor=[UIColor whiteColor];
self.label.text = #"Hello";
[self.imageCarouselScrollView addSubview:self.label];
[self bringSubviewToFront:self.label];
self.titleLabelTopConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20];
NSLayoutConstraint *titleLeadingConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:20];
[self addConstraints:#[self.titleLabelTopConstraint,titleLeadingConstraint]];
You have to include a constraint to the right (for horizontal scrolling) or bottom (for vertical scrolling) of the scroll view so that it can deduce the content size.
I try comment your code:
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; //if 'translatesAutoresizingMaskIntoConstraints=NO' frame not work work anymore. Use CGRectZero instead
self.label.translatesAutoresizingMaskIntoConstraints = NO;
self.label.backgroundColor = [UIColor clearColor];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.textColor=[UIColor whiteColor];
self.label.text = #"Hello";
[self.imageCarouselScrollView addSubview:self.label]; //Your self.label added on 'self.imageCarouselScrollView' but your constraints added on self
[self bringSubviewToFront:self.label]; // ??? Why?
self.titleLabelTopConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20]; //it constrain means: "self view top edge equal to self.imageCarouselScrollView bottom + offset 20 "
NSLayoutConstraint *titleLeadingConstraint = [NSLayoutConstraint
constraintWithItem:self
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.imageCarouselScrollView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:20];//it constrain means: "self view Leading edge equal to self.imageCarouselScrollView Trailing + offset 20 "
[self addConstraints:#[self.titleLabelTopConstraint,titleLeadingConstraint]];
And now i have few questions:
Why constraints for self.label?? Because after translatesAutoresizingMaskIntoConstraints=no it frame equals 0; You didn't see label anymore.
You have 2 constraints what about other edges????
No question, council, try use 'constraintsWithVisualFormat:options:metrics:views:'

Resources