I have a view that is pushed onto navigation stack like this:
FriendsDetailViewController *detail = [[FriendsDetailViewController alloc] init];
detail.user = selectedUser;
[self.navigationController pushViewController:detail animated:YES];
Inside a view controller, I have two elements: my custom controls view, that is a view with two buttons and a label inside, and a table view. I am setting constraints to them as shown:
-(void)setupView {
self.tableView = [[UITableView alloc] init];
self.tableView.dataSource = self;
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.tableView];
self.controlsView = [[ControlsView alloc] init];
self.controlsView.player = self.player;
self.controlsView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.controlsView];
[self setControlsViewConstraints];
[self setTableViewConstraints];
}
-(void)setTableViewConstraints {
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.controlsView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.tableView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraints:#[topConstraint, leadingConstraint, trailingConstraint, bottomConstraint]];
}
-(void)setControlsViewConstraints {
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.controlsView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:self.controlsView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self.controlsView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:self.controlsView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:30];
[self.view addConstraints:#[top, leading, trailing, height]];
}
But by the end I get unexpected result.
Firstly, my custom controls view is black, although in code the background color is set to white. Secondly, custom controls view is situated just as I expected, but my table View is messed up. Somehow it does not sit on the bottom of my controls view.
I have other view controller without an embedded navigation controller, and the layout is just fine.
It seems like I don't catch how navigation view is embedded in my view controller. I do the whole project without Interface builder, and this strange behavior is really confusing.
Since iOS7, view controllers set scrollViews insets if there's a navigation bar, to make the content go behind the blurred bar (see https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/instp/UIViewController/automaticallyAdjustsScrollViewInsets)
so to fix your tableView you just need to set self.automaticallyAdjustsScrollViewInsets = NO
For the color of the other view, it's weird, but nothing in the code you posted changes the backgroundColor, are you sure you're setting it somewhere else?
Related
I have added UIViewand UIScrollviewinside that UIViewusing IB.This is my view hierarchy.
Now I am adding UIViews into my UIScrollViewprogrammatically and im adding constraints programmatically like this.
-(void)loadLeavesBlocks
{
for(int x=0;x<[arrayToday count];x++)
{
vwBlock=[[UIView alloc] initWithFrame:CGRectMake(blockX, blockY, blockWidth, 250.0)];
vwBlock.translatesAutoresizingMaskIntoConstraints = NO;
[vwBlock setBackgroundColor:[UIColor whiteColor]];
[_mainScroll addSubview:vwBlock];
NSLayoutConstraint *top = [NSLayoutConstraint
constraintWithItem:vwBlock
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_segmentedControl
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:blockY];
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:vwBlock
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:_mainScroll
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:blockX];
NSLayoutConstraint *trailling = [NSLayoutConstraint
constraintWithItem:vwBlock
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:_mainScroll
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:10.f];
//Height to be fixed for SubView same as AdHeight
NSLayoutConstraint *height = [NSLayoutConstraint
constraintWithItem:vwBlock
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0
constant:250.f];
[_mainScroll addConstraint:top];
[_mainScroll addConstraint:leading];
[_mainScroll addConstraint:trailling];
[vwBlock addConstraint:height];
blockY=blockY+260;
}
[hud removeFromSuperview];
}
But I am getting this error.
The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x15eddb560 V:[UISegmentedControl:0x15eda4bc0]-(0)-[UIView:0x15edc3a50]>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
Please help me.
Thanks
I have a view called profile which is taking (0,0,320,60) size in storyboard which is taking full width but 60 height, and i am trying to place another view called ranking inside it at the center and what ever the device is iPhone4s,5s,6s,6 it should just take my view and put it at the center.
Here is what i tried:
ranking.frame = CGRectMake(0, 0, 120, 60);
ranking.center = self.Profile.center;
The current code is not centering my view In all devices. what can i do to do it dynamically ?
You can use AutoLayout with the following method:
+ (void)centerView:(UIView *)view inContainerView:(UIView *)containerView withSuperView:(UIView *)superView
{
[superView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
[superView addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
}
You can add the method above in your ViewController or in a helper class.
Remember to set the translatesAutoresizingMaskIntoConstraints property to false before using AutoLayout on your view.
So if ranking is your subview and self.Profile is your superView you can do the following.
UIView *ranking = [[UIView alloc] init];
ranking.translatesAutoresizingMaskIntoConstraints = false;
[self.Profile addSubview:ranking];
[[self class] centerView:ranking inContainerView:self.Profile withSuperView:self.Profile];
[self.Profile addConstraint:[NSLayoutConstraint constraintWithItem:ranking attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:120]];
[self.Profile addConstraint:[NSLayoutConstraint constraintWithItem:ranking attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:60]];
In my application I have inserted UIViews on view controller. My main requirement is that I want to set equal widths for both UIViews using auto-layouts "Constraint with item format".
For this I have written some code but I did not get equal widths. What did I do here wrong?
I want get result like below image (i.e need to set equal widths for both UIViews).
My code:
#import "ViewController8.h"
#interface ViewController8 ()
{
UIView * myView1;
UIView * myView2;
}
#end
#implementation ViewController8
- (void)viewDidLoad {
[super viewDidLoad];
myView1 = [[UIView alloc] init];
myView1.backgroundColor = [UIColor lightGrayColor];
myView1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView1];
myView2 = [[UIView alloc] init];
myView2.backgroundColor = [UIColor redColor];
myView2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:myView2];
[self operation2];
}
-(void)operation2
{
//Applying autolayouts for myview2
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
//Applying autolayouts for myview1
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:-30]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-30]];
}
Equal width constraint is not there in your posted code. Try adding this
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:myView2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView1
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
It's enough to add the equal-width constraint
[NSLayoutConstraint constraintWithItem:myView1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:myView2
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
You must not define the width of the two views explicitly using constraints because view1 is pinned to the leading edge of the superview, view2 is pinned to the trailing edge of the superview and the trailing edge of view1 is pinned to the leading edge of view2. Hence, the constraint system is fully determined after adding the above equal-width constraint.
This is what adding the constraint will lead to:
Contemporary solution is using NSLayoutAnchor
myView1.widthAnchor.constraint(equalTo: myView2.widthAnchor)
don't forget to activate this using isActive = true, or via NSLayoutConstraint.activate().
I am new for auto-layouts and i am trying to add one container view on ScrollView using auto-layouts "constraint with item" formate but I can't adding using my code.
I know how to add using visual formate but I want to do this process using constraint with item formate. Please help me!
My code:
#import "ViewController3.h"
#interface ViewController3 ()
{
UIScrollView * scrollView;
UIView * containerView;
}
#end
#implementation ViewController3
- (void)viewDidLoad {
[super viewDidLoad];
scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor lightGrayColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
containerView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor orangeColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:containerView];
//Applying autolayouts for scrollview
NSLayoutConstraint * constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem: self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
//Applying autolayouts for containerview
NSLayoutConstraint * constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem: scrollView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
}
With Autolayout, you don't need to set scrollview's contentSize explicitly, but you have to provide enough clues to let Autolayout system infer what exactly your scrollview's contentSize is.
There are generally two ways to layout UIScrollView with Autolayout, mixed or pure Autolayout.Check this:https://developer.apple.com/library/ios/technotes/tn2154/_index.html.
If it is pure Autolayout, you can achieve that by your containerView's subviews, that is, your subviews do not rely on the scroll view to get their size. Or you can just tie your containerView's width and height to any view outside your scrollview, like self.view, or to a fixed value.
E.g,
You can add four more lines :
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
[self.view addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
[self.view addConstraint:constraint2];
How to add constraint for subview of view controller
explain briefly
// create a new view
self.containerView = [UIView new];
// before adding constraints always add respective view to superview
[self.view addSubview:self.containerView];
[self.containerView setTranslatesAutoresizingMaskIntoConstraints:false];
// add container on newly added view
NSLayoutConstraint *topConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leadingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
NSLayoutConstraint *trailingConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.containerView.superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraintContainer = [NSLayoutConstraint constraintWithItem:self.containerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.bottomLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
// add constraint to superview of respective view
[self.view addConstraints:#[topConstraintContainer,leadingConstraintContainer,trailingConstraintContainer,bottomConstraintContainer]];
There are alot of possibilities, but this is the main flow
Also there are third party libraries available which makes adding constraints easier, like
PureLayout