Issue with autoLayout and constraints - ios

I have an issue with iOS and AutoLayout...it is a testing application where I have replicated the problem. It consists in a simple view controller, containing a fixed UIButton; when user clicks this button, the delegate have to create a custom view, apply it positioning constraints; the view has then a method to build his content views, and the child views are placed with constraints too.
Here is the code:
//MyViewController.m
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *start_but = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 100, 40)];
[start_but setTitle:#"Draw" forState:UIControlStateNormal];
[start_but setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
[start_but addTarget:self action:#selector(clickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:start_but];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)clickAction: (id)sender
{
localView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];
UIView *superview = (UIView*)localView;
superview.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:localView];
NSLayoutConstraint *constr = [NSLayoutConstraint constraintWithItem:localView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100.0];
[self.view addConstraint:constr];
constr = [NSLayoutConstraint constraintWithItem:localView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:-50.0];
[self.view addConstraint:constr];
[localView CreateGuiInterface];
}
#end
//MyView.m
#implementation MyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
}
return self;
}
-(void)CreateGuiInterface
{
UIView *superview = self;
self.backgroundColor = [UIColor redColor];
UIButton *but1 = [[UIButton alloc] init];
[but1 setTitle:#"Button" forState:UIControlStateNormal];
[but1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
but1.backgroundColor = [UIColor yellowColor];
but1.translatesAutoresizingMaskIntoConstraints = NO;
[superview addSubview:but1];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:but1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight multiplier:1.0
constant:-20.0];
[superview addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:but1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:50.0];
[superview addConstraint:constraint];
UILabel *label = [[UILabel alloc] init];
label.text = #"Label";
label.backgroundColor = [UIColor greenColor];
label.textColor = [UIColor blackColor];
label.translatesAutoresizingMaskIntoConstraints = NO;
[superview addSubview:label];
constraint = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:but1
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:-40.0];
[superview addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:but1
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20.0];
[superview addConstraint:constraint];
}
#end
So, the problem is that when i click iOS seems to have problem to draw the view background color. It is strange, 'cause if i don't use superview.translatesAutoresizingMaskIntoConstraints = NO and put the view in a fixed place (with initWithFrame:CGRect(100,200,300,400) for example) without using constraints, it works fine: can there be problems using constraints in child and parent views? AppleDoc said that the constraints cannot pass throughout the view barrier; so i've written my app with local-view oriented constraints....
can somebody help me?
thanks in advice

The intent with autoLayout is to never have to setFrame on any of your views. If you want to place your view programatically within your superview, you will provide constraints for that. The changes I made you will see the background red as intended. I didn't change your MyView implementation (simply added -(void)CreateGuiInterface;
within MyView.h). The changes I made to demonstrate are within your MyViewController implementation.
Try the following code in place of your viewController:
#interface MyViewController ()
#property (nonatomic, strong) MyView* localView;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *start_but = [[UIButton alloc] init];
start_but.translatesAutoresizingMaskIntoConstraints = NO;
[start_but setTitle:#"Draw" forState:UIControlStateNormal];
[start_but setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
[start_but addTarget:self action:#selector(clickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:start_but];
// The following constraints simply place the initial start button in the top left
NSDictionary* views = NSDictionaryOfVariableBindings(start_but);
NSString* format = #"H:|-[start_but]";
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:format
options:0
metrics:nil
views:views];
[self.view addConstraints:constraints];
format = #"V:|-[start_but]";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format
options:0
metrics:nil
views:views];
[self.view addConstraints:constraints];
}
- (void)clickAction: (id)sender
{
self.localView = [[MyView alloc] init];
UIView *superview = (UIView*)self.localView;
superview.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.localView];
// Here I'm placing your parent view (MyView) 50 points on right of the superview with
// a width of 400 points
NSDictionary* views = NSDictionaryOfVariableBindings(superview);
NSString* format = #"H:[superview(==400)]-(50)-|";
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:format
options:0
metrics:nil
views:views];
[self.view addConstraints:constraints];
// Vertically 100 points from the top of the superview with a height of 300 points
format = #"V:|-(100)-[superview(==300)]";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format
options:0
metrics:nil
views:views];
[self.view addConstraints:constraints];
[self.localView CreateGuiInterface];
}
#end

Related

Objective C: Center with NSLayoutConstraint

NSArray *imageViewHorConst2 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:[_startbutton(50)]-30-[_resetbutton(50)]" options:0 metrics:nil views:viewsDictionary2];}
I'm trying to get those 2 buttons (startbutton, resetbutton) to be separated by some value and be centred.
I'm not sure how to do this in objective C
Here is the snippet to add the two buttons in the center of the screen separated by 30 pixels:
UIButton *button1 = [[UIButton alloc] init];
button1.translatesAutoresizingMaskIntoConstraints = FALSE;
[button1 setTitle:#"Button 1" forState:UIControlStateNormal];
button1.backgroundColor = [UIColor blueColor];
UIButton *button2 = [[UIButton alloc] init];
button2.translatesAutoresizingMaskIntoConstraints = FALSE;
[button2 setTitle:#"Button 2" forState:UIControlStateNormal];
button2.backgroundColor = [UIColor brownColor];
// Add a container view to hold two buttons
UIView *containerView = [[UIView alloc] init];
containerView.translatesAutoresizingMaskIntoConstraints = FALSE;
[containerView addSubview:button1];
[containerView addSubview:button2];
// vertical constraints
[containerView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[button1]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(button1)]];
[containerView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[button2]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(button2)]];
// horizontal constraints
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[button1]-(30)-[button2]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(button1, button2)]];
// Add the container view with centerx and centery constraints to
// keep the buttons in the center
[self.view addSubview:containerView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
Screenshot:
You can easily accomplish this with UIStackView
self.view.backgroundColor = [UIColor redColor];
UIStackView*st = [UIStackView new];
st.distribution = UIStackViewDistributionFillEqually;
st.axis = UILayoutConstraintAxisHorizontal;
st.spacing = 40;
UIButton*b1 = [UIButton buttonWithType:UIButtonTypeSystem];
UIButton*b2 = [UIButton buttonWithType:UIButtonTypeSystem];
[b1 setTitle:#"ClickB1" forState:UIControlStateNormal];
[b2 setTitle:#"ClickB2" forState:UIControlStateNormal];
st.translatesAutoresizingMaskIntoConstraints = NO;
b1.translatesAutoresizingMaskIntoConstraints = NO;
b2.translatesAutoresizingMaskIntoConstraints = NO;
[st addArrangedSubview:b1];
[st addArrangedSubview:b2];
[self.view addSubview:st];
[[st.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];
[[st.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];

How to change scrollView content sizes using auto-layouts in ios

I am adding 3 UITextfields and 1 UIButton on my scrollview.
My main requirement is when I click on UITextfield scroll must scroll up-to all fields visible to user above keyboard.
And when I click return button on keyboard scroll must scroll by default what in set for scrollview contentSize using auto-layouts.
my code:
#interface ViewController10 ()
{
UIScrollView * scrollView;
UITextField * emailTextField;
UITextField * nameTextField;
UITextField * passwword;
UIButton * submit;
}
#end
#implementation ViewController10
- (void)viewDidLoad {
[super viewDidLoad];
scrollView = [[UIScrollView alloc] init];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
emailTextField = [self createLabelWithText];
emailTextField.delegate = self;
[scrollView addSubview: emailTextField];
nameTextField = [self createLabelWithText];
nameTextField.delegate = self;
[scrollView addSubview: nameTextField];
passwword = [self createLabelWithText];
passwword.delegate = self;
[scrollView addSubview: passwword];
submit = [[UIButton alloc]init];
submit.backgroundColor = [UIColor orangeColor];
[submit setTitle: #"Submit" forState: UIControlStateNormal];
submit.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:submit];
NSDictionary * viewsDic = NSDictionaryOfVariableBindings(scrollView,emailTextField,nameTextField,passwword,submit);
//Applying autolayouts for scrolview
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[scrollView]-0-|"]
options:0
metrics:nil
views:viewsDic]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-0-[scrollView]-0-|"]
options:0
metrics:nil
views:viewsDic]];
//Applying autolayouts for textfields and button
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:emailTextField
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
NSArray * keys = #[#"emailTextField",#"nameTextField",#"passwword",#"submit"];
for (NSString * key in keys) {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-10-[%#]-10-|",key]
options:0
metrics:nil
views:viewsDic]];
}
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-30-[emailTextField(30)]-130-[nameTextField(30)]-130-[passwword(30)]-60-[submit(30)]-20-|"
options:0
metrics:nil
views:viewsDic]];
}
-(UITextField *)createLabelWithText{
UITextField * textfield = [[UITextField alloc] init];
textfield.textColor = [UIColor whiteColor];
textfield.backgroundColor = [UIColor lightGrayColor];
textfield.translatesAutoresizingMaskIntoConstraints = NO;
return textfield;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
scrollView.contentSize = CGSizeMake(320, 700);
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
Please check this awsome tutorial , it is definetly helpfull for you.
**
Using UIScrollView with Auto Layout in iOS
**
as said in blog you need to set constrain in this way when you are using autolayout.
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:0
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0];
[self.view addConstraint:leftConstraint];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:0
toItem:self.view
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0];
[self.view addConstraint:rightConstraint];
change value and name according to your requirement.
When keyBoards is appears .
CGRect frame = currentActiveView.frame; // your scrollview frame
frame.size.height = SCREEN_HEIGHT - 216 - keyboardAccesssory.frame.size.height;
currentActiveView.frame = frame;
[yourScrollView setContentSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT)];
When keyboard is resign ..
CGRect frame = currentActiveView.frame; // your scrollview frame
frame.size.height = SCREEN_HEIGHT;
currentActiveView.frame = frame;
[yourScrollView setContentSize:CGSizeMake(SCREEN_WIDTH, SCREEN_HEIGHT)];
You need to play with the frame of the view.
Move the frame above keyboard when keyboard is shown whereas reset its position when keyboard is hidden.
You need to do it programmatically.
You can also go through Apple's Programming guide. https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html#//apple_ref/doc/uid/TP40009542-CH5-SW3

Positioning UIButtons at top of Screen

What I want is to have 5 buttons equally spaced out at the top of the screen. I tried using constraints but the buttons would get squished.
I have this code so far:
- (void)viewDidLoad {
[super viewDidLoad];
//I know this is only two buttons
NSUInteger space = (_backround.frame.size.width - _squareOne.frame.size.width * 5) / 6;
CGRect newFrameOne;
newFrameOne = CGRectMake(space, 50, 55, 55);
CGRect newFrameTwo;
newFrameTwo = CGRectMake(space * 2 + _squareOne.frame.size.width, 50, 55, 55);
_squareOne.frame = newFrameOne;
_squareTwo.frame = newFrameTwo;
}
The buttons never show up... and I don't know any other ways to do this...
Any help?
Could you try something like this below?
Update: I've written the code properly using Xcode this time (previously I typed it from memory).
See below screenshot for the final result.
View Controller Header File
#interface ViewController : UIViewController
#property (nonatomic, strong) UIButton *btn1;
#property (nonatomic, strong) UIButton *btn2;
#property (nonatomic, strong) UIButton *btn3;
#property (nonatomic, strong) UIButton *btn4;
#property (nonatomic, strong) UIButton *btn5;
#end
View Controller Implementation File
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
}
-(void)initViews
{
self.btn1 = [[UIButton alloc] init];
self.btn1.backgroundColor = [UIColor grayColor];
self.btn2 = [[UIButton alloc] init];
self.btn2.backgroundColor = [UIColor grayColor];
self.btn3 = [[UIButton alloc] init];
self.btn3.backgroundColor = [UIColor grayColor];
self.btn4 = [[UIButton alloc] init];
self.btn4.backgroundColor = [UIColor grayColor];
self.btn5 = [[UIButton alloc] init];
self.btn5.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.btn1];
[self.view addSubview:self.btn2];
[self.view addSubview:self.btn3];
[self.view addSubview:self.btn4];
[self.view addSubview:self.btn5];
}
-(void)initConstraints
{
self.btn1.translatesAutoresizingMaskIntoConstraints = NO;
self.btn2.translatesAutoresizingMaskIntoConstraints = NO;
self.btn3.translatesAutoresizingMaskIntoConstraints = NO;
self.btn4.translatesAutoresizingMaskIntoConstraints = NO;
self.btn5.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"btn1": self.btn1,
#"btn2": self.btn2,
#"btn3": self.btn3,
#"btn4": self.btn4,
#"btn5": self.btn5
};
// horizontal constraints
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[btn1]-5-[btn2(==btn1)]-5-[btn3(==btn1)]-5-[btn4(==btn1)]-5-[btn5(==btn1)]-5-|" options:0 metrics:nil views:views]];
// vertical constraints
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.btn1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:5.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.btn2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.btn1 attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.btn3 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.btn1 attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.btn4 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.btn1 attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.btn5 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.btn1 attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
}
Result
This is what I get.
What long black strip are you referring to, the battery indicator?

iOS Auto layout Rows

I'm trying to understand auto layout better and I created some static methods that can help me out. Now I'm trying to setup an array of views in like a tableview structure (in rows). This works kinda.
See here my problem:
To achieve this I use this code:
//In the update constraints method
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
//The row method
+ (NSArray *) row:(NSArray const *)views inView:(UIView const *)superview {
NSMutableArray *constraints = [NSMutableArray new];
CGFloat multiplier = 1.f / [views count];
UIView *prev = nil;
for (UIView *view in views) {
if (!view.hidden) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f]];
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeHeight multiplier:multiplier constant:0.f]];
if (prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}
prev = view;
}
}
return [constraints copy];
}
So this part works (I guess). But when I want to split the yellow view again in rows. The views are always added into the top region?
In the update constraints method I do this:
UIView *view1 = [self createView];
view1.backgroundColor = [UIColor redColor];
UIView *view2 = [self createView];
view2.backgroundColor = [UIColor yellowColor];
[self addSubview:view1];
[self addSubview:view2];
UIView *view3 = [self createView];
UIView *view4 = [self createView];
[view2 addSubview:view3];
[view2 addSubview:view4];
[self addConstraints:[DXVFL row:#[view1, view2] inView:self]];
[view2 addConstraints:[DXVFL row:#[view3, view4] inView:view2]];
But I want those two rows in the bottom? What am I doing wrong?
Off the top of my head:
You need to add a constraint to tell it to align the view to the top of the superview. At the moment, you just set the height and width but you don't tell it where to put its top edge.
Try changing your code to this:
if (!prev) {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
} else {
[constraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prev attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}

Autolayout Issue in UIView

I am here to get help for a simple problem.My app runs in both 3.5" and 4" screens but the view is not centred in both the sizes(check images for the view).I am using auto layout and also tried to reset suggested constraints.When i bring the label to centre in one view it is not positioned correctly in the other view.Please help i am stuck
You need to add 4 constraints to the view which needs to be centered.
Pin:
1. Width.
2. Height.
Align:
3. Horizontal center in container.
4. Vertical center in container.
Wrap all your subviews except the red grandient background inside a container UIView:
#property (nonatomic, strong) UIView *container;
[self.container addSubview:greyBox];
[self.container addSubview:getStarted];
...
[self.view addSubview:self.redBG];
[self.view addSubview:self.container];
Update your constraints to be relative to your container view instead of self.view.
Then center your container view to your self.view:
// ---------------------------------------------------------------
// centers the container view to your view controller's vivew
// ---------------------------------------------------------------
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.container attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
That way, your subview always appear to be centered.
I think the problem you're having at the moment is that you 'offset' each subview's y position relative to the self.view's top edge. You might get it right on one screen, but then when your screen gets longer, it appears wrong.
Using the above view container method, lets you dynamically add as much subviews as you like and it is still centered, assuming your subviews are connected to the container view's top and bottom edges like a tent.
Floating subviews inside a container view will cause the container to have 0 height and not work.
Update
Not sure how you've setup your IB constraints, you might want to show screenshots of them.
Perhaps you have not setup your constraints properly in IB. Maybe you can improve your constraint settings similar to the ones I've provided below to see if it fixes it.
This is a demo of the method I mentioned above:
4 inch iPhone screen:
3.5 inch iPhone screen:
Notice how both screenshot shows the white box being centered in the view.
This is the code I used:
Header File
// HEADER FILE
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController
#property (nonatomic, strong) UIView *gradient;
#property (nonatomic, strong) UIView *container;
#property (nonatomic, strong) UIView *whiteBox;
#property (nonatomic, strong) UILabel *label1;
#property (nonatomic, strong) UIButton *getStarted;
#property (nonatomic, strong) UILabel *label2;
#end
Implementation File
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self initView];
[self initConstraints];
}
-(void)initView
{
self.gradient = [[UIView alloc] init];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = self.view.frame;
UIColor *redColor = [UIColor colorWithRed:157.0/255.0 green:37.0/255.0 blue:29.0/255.0 alpha:1.0];
UIColor *pinkColor = [UIColor colorWithRed:216.0/255.0 green:101.0/255.0 blue:100.0/255.0 alpha:1.0];
gradientLayer.startPoint = CGPointMake(0.5, 0.0);
gradientLayer.endPoint = CGPointMake(0.5, 1.0);
gradientLayer.colors = #[(id)redColor.CGColor,
(id)pinkColor.CGColor,
(id)redColor.CGColor];
[self.gradient.layer insertSublayer:gradientLayer atIndex:0];
// container view
self.container = [[UIView alloc] init];
// white box
self.whiteBox = [[UIView alloc] init];
self.whiteBox.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0];
self.whiteBox.layer.shadowColor = [UIColor blackColor].CGColor;
self.whiteBox.layer.shadowOffset = CGSizeMake(0.0, 3.0);
self.whiteBox.layer.shadowOpacity = 0.5;
self.whiteBox.layer.shadowRadius = 3.0;
self.label1 = [[UILabel alloc] init];
self.label1.text = #"Label 1 Text Goes Here";
self.label1.textAlignment = NSTextAlignmentCenter;
self.label1.textColor = redColor;
self.getStarted = [[UIButton alloc] init];
[self.getStarted setTitle:#"Get Started" forState:UIControlStateNormal];
[self.getStarted setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.getStarted.backgroundColor = redColor;
self.label2 = [[UILabel alloc] init];
self.label2.text = #"Version 1.3 (log enabled)";
self.label2.textAlignment = NSTextAlignmentCenter;
self.label2.textColor = [UIColor darkGrayColor];
self.label2.font = [UIFont fontWithName:#"Arial" size:14];
[self.whiteBox addSubview:self.label1];
[self.whiteBox addSubview:self.getStarted];
[self.whiteBox addSubview:self.label2];
[self.container addSubview:self.whiteBox];
[self.view addSubview:self.gradient];
[self.view addSubview:self.container];
}
-(void)initConstraints
{
self.gradient.translatesAutoresizingMaskIntoConstraints = NO;
self.container.translatesAutoresizingMaskIntoConstraints = NO;
self.whiteBox.translatesAutoresizingMaskIntoConstraints = NO;
self.label1.translatesAutoresizingMaskIntoConstraints = NO;
self.getStarted.translatesAutoresizingMaskIntoConstraints = NO;
self.label2.translatesAutoresizingMaskIntoConstraints = NO;
id views = #{
#"gradient": self.gradient,
#"container": self.container,
#"whiteBox": self.whiteBox,
#"label1": self.label1,
#"getStarted": self.getStarted,
#"label2": self.label2
};
// gradient constraint
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[gradient]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[gradient]|" options:0 metrics:nil views:views]];
// container constraitns
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.container
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.container
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
// white box constraints
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[whiteBox(280)]-10-|" options:0 metrics:nil views:views]];
[self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[whiteBox]-10-|" options:0 metrics:nil views:views]];
// white box subview constraints
[self.whiteBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[label1]-10-|" options:0 metrics:nil views:views]];
[self.whiteBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[getStarted]-10-|" options:0 metrics:nil views:views]];
[self.whiteBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[label2]-10-|" options:0 metrics:nil views:views]];
[self.whiteBox addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[label1]-20-[getStarted(40)]-15-[label2]-5-|" options:0 metrics:nil views:views]];
}

Resources