I'm quite surprised. I didn't find anything remotely tackling the issue on SO. I would have imagined that many people may have tried that before me. That must only mean one thing ... It's trivial and I can't make it :(
How do I add constraints to the cameraOverlay ?
I tried this
UIView *overlayView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
[overlayView setBackgroundColor:[UIColor redColor]];
[overlayView setAlpha:0.5];
UILabel *Testlabel = [[UILabel alloc] init];
[Testlabel setText:#"Hollllaaaaa in the overlay"];
[overlayView addSubview:Testlabel];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:overlayView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:Testlabel
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
[overlayView addConstraints:#[widthConstraint]];
[self.picker setCameraOverlayView:overlayView];
But I get the error Unable to simultaneously satisfy constraints. With just one constraint.
As a note, the picker is part of a view that has constraints and are well defined. I am wondering if the fact that I initwithFrame the overlay view has something to do with autolayout not liking that ... If that the case, how can I simply add a constraint to a blank overlay that would have the same size as the screen ?
Related
I am trying to programmatically set the UIButton vertically and horizontally in centre using AutoLayouts here is my code:
- (void)awakeFromNib {
UIView *av = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 35.0)];
UIButton *doneButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 37, 30)];
//UIButton title, color, backgroung color, targer action ...
NSLayoutConstraint* cn3 = [NSLayoutConstraint constraintWithItem:doneButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:av
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[av addConstraint:cn3];
NSLayoutConstraint* cn4 = [NSLayoutConstraint constraintWithItem:doneButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:av
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
[av addConstraint:cn4];
[av addSubview:doneButton];
self.theTextField.inputAccessoryView = av;
}
The above code is working fine except one thing, I am getting this warning in console:
The view hierarchy is not prepared for the constraint:
NSLayoutConstraint:0x7fcfc494efb0
UIButton:0x7fcfc2624420'Done'.centerX ==
UIView:0x7fcfc2624230.centerX
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.
And getting same warning for Y.
Please tell me what is going wrong why I am getting this warning?
Add doneButton to the av view before setting your constraints.
[av addSubview:doneButton];
[av addConstraint:cn3];
[av addConstraint:cn4];
I am having a strange problem with UIBarButtonItem. I am creating one with a custom view, and the view is of my own MyCustomView type. It contains couple of labels and some other subviews. Whenever I use autolayout in this custom view class to lay out the subviews - the button is displayed on top-left corner of the screen! You can see it in the picture below - MyCustomView just has one subview with gray background and I use autolayout to stretch it to fill the parent MyCustomView:
When I don't use autolayout everything is fine and the button is displayed normally:
Can anyone explain me what is going on here and am I allowed to use autolayout in custom views which are going to be put in UIBarButtonItems (maybe not on the topmost level) ?
UPDATE: this happens after I do
self.translatesAutoresizingMaskIntoConstraints = NO;
in MyCustomView - in the top view which should be placed in bar button. I am doing it to make the system call my intrinsicContentSize method. I guess using the old sizeThatFits: instead would still be ok.
UPDATE 2: Here is the test code:
UIControl *cus = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 22, 22)];
// uncomment the following line to mess everything
//cus.translatesAutoresizingMaskIntoConstraints = NO;
cus.backgroundColor = [UIColor redColor];
UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = #"Q";
[label sizeToFit];
label.font = [UIFont systemFontOfSize:18];
[cus addSubview:label];
NSLayoutConstraint *centerX1 = [NSLayoutConstraint constraintWithItem:cus
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:label
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
NSLayoutConstraint *centerY1 = [NSLayoutConstraint constraintWithItem:cus
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:label
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
[cus addConstraints:#[centerX1, centerY1]];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:cus];
controller.navigationItem.rightBarButtonItem = barButton;
I would be happy to get explanations to understand what is going on.
i am trying to add button inside the scrollview with center constrain,
constrain working but scroll not working scroll become stuck,
Anyone can help me where is mistake,
-(void)viewDidLoad{
scrllview = [[UIScrollView alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]];
scrllview.backgroundColor = [UIColor orangeColor];
self.view=scrllview;
[scrllview setContentSize:CGSizeMake(300, 1000)];
submitButton = [UIButton buttonWithType:UIButtonTypeCustom];
[submitButton setTitle:#"connect" forState:UIControlStateNormal];
[submitButton.titleLabel setFont:[UIFont fontWithName:#"HelveticaNeue-Bold" size:14.0]];
[submitButton addTarget:self
action:#selector(myMethod:)
forControlEvents:UIControlEventTouchUpInside];
submitButton.backgroundColor = [UIColor blackColor];
submitButton.translatesAutoresizingMaskIntoConstraints = NO ;
[scrllview addSubview:submitButton];
NSLayoutConstraint *constraint = [NSLayoutConstraint
constraintWithItem:submitButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:scrllview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f];
[scrllview addConstraint:constraint];
constraint = [NSLayoutConstraint
constraintWithItem:submitButton
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:scrllview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f];
[scrllview addConstraint:constraint];
}
While you are using scrollview with autolayout, you should not use contentsize.
You can create a view inside scroll view, which should have your required height and constraint relative to scrollview. You can add your button inside that view.
It will work. I have implemented it with xib. Same issue while adding control directly in scrollview. I used view inside scrollview and added required control to view.
Auto layout UIScrollView with subviews with dynamic heights
In my table view's cellForRowAtIndexPath: method I have the following code to add an image and align it in the cell:
UIImageView *PocketIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pocket-icon"]];
[cell addSubview:PocketIcon];
NSLayoutConstraint *iconDistanceFromCellTopConstraint = [NSLayoutConstraint constraintWithItem:PocketIcon attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeTop multiplier:1.0 constant:14.0];
[cell addConstraint:iconDistanceFromCellTopConstraint];
NSLayoutConstraint *iconDistanceFromCellLeftConstraint = [NSLayoutConstraint constraintWithItem:PocketIcon attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeLeft multiplier:1.0 constant:22.0];
[cell addConstraint:iconDistanceFromCellLeftConstraint];
However each time the image does indeed get added, but it just sits in the top left corner of the cell. What's wrong with the above code that's causing the constraint not to work?
Your code works for me after setting translatesAutoresizingMaskIntoConstraints to NO:
UIImageView *PocketIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pocket-icon"]];
PocketIcon.translatesAutoresizingMaskIntoConstraints = NO;
[cell addSubview:PocketIcon];
Another little advice I'd like to give. I use constrains extensively and my life became much easier after I started using category for working with constraints, this one:
https://github.com/PureLayout/PureLayout
I suggest you try it too.
So add your imageView and constraints to cell.contentView not cell ( [cell.contentView addSubview:PocketIcon];). Also you want to turn off AutoresizingMask, so add this[PocketIcon setTranslatesAutoresizingMaskIntoConstraints:NO] . You may need a bool to make sure not to add the constraints more then once as the table is scrolled.
I am working with a grouped table, and am customizing the header in the sections using tableView: viewForHeaderInSection: method and setting the height using tableView: heightForHeaderInSection:.
I created a view and placed a label in it like so:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
// Create a custom title view.
UIView *ctv;
UILabel *titleLabel;
// Set the name.
{...} // Code not relevant
// If an iPhone.
if ([Config isPhone]) {
ctv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 14, 320, 36)];
}
// If an iPad
else {
ctv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 75)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 544, 55)];
}
// Config the label.
{...} // Code not relevant
// Center the items.
ctv.center = CGPointMake(tableView.center.x, ctv.center.y);
titleLabel.center = ctv.center;
// Add the label to the container view.
[ctv addSubview:titleLabel];
// Return the custom title view.
return ctv;
}
This all works great until you rotate the screen. The position is off. I realize that this is because the view is being centered while it is in the other orientation causing the calculation of the center to no longer be correct. The solution should be to add a constraint. I tried adding the constraint below:
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(ctv);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|[ctv]|"
options:0
metrics:nil
views:viewsDictionary
];
[tableView addConstraints:constraints];
But when I do this trying the method below, I get that no parent view is associated with it, which makes complete sense, because it doesn't technically get added into the view is returned. So I thought I would try to add the constraint this way:
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:ctv
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:tableView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0
];
[tableView addConstraint:constraint];
But this one also errors. I've tried switching the tableView variables to the global table property but it gives the same results. I also tried to figure out how to add the constraint in the view did load method but it failed as I could not figure out how to get back to the table's section headers from the table object. The last thought I had was to set the width on the table in a constraint and set one to center the entire table. This process worked but now I have the an ugly scroll in the middle of my app when it is in the landscape orientation. So the question is, where/how can I access the individual section headers after they have been loaded to add this constraint? I'm still pretty new to Objective-C so any help is appreciated.
***** NEW CODE BASED FROM rdelmar SUGGESTION ****
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *ctv = [tableView dequeueReusableHeaderFooterViewWithIdentifier:#"groupHeader"];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 544, 55)];
[titleLabel setTranslatesAutoresizingMaskIntoConstraints: NO];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:ctv
attribute:NSLayoutAttributeCenterX
relatedBy:0
toItem:titleLabel
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0
];
[ctv addConstraints:#[constraint]];
titleLabel.text = #"string";
[ctv addSubview:titleLabel];
return ctv;
}
But like I mentioned, it is giving me a "Constraint must contain a first layout item" error.
I did it this way in a recent project to add a label and a UIActivityIndicatorView:
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:#"Header"];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0,0, 250, 20)];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:label attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeLeft relatedBy:0 toItem:label attribute:NSLayoutAttributeLeading multiplier:1 constant:-10];
[headerView addConstraints:#[con1,con2]];
label.text = #"Pick an Activity from the List";
label.backgroundColor = [UIColor clearColor];
[headerView addSubview:label];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[spinner setTranslatesAutoresizingMaskIntoConstraints:NO];
if (activityIndicatorShouldStop == NO) [spinner startAnimating];
[headerView addSubview:spinner];
NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:spinner attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeRight relatedBy:0 toItem:spinner attribute:NSLayoutAttributeTrailing multiplier:1 constant:10];
[headerView addConstraints:#[con3,con4]];
return headerView;
}
If you can't get the constraints to work, your original code supplemented by an autoresizing mask (flexible left and right margins) would do the job.
An even simpler solution would be to return a UILabel as the header view, with centered text.
Your first attempt at constraints wouldn't work because you are setting them up wrong.
The table view is responsible for setting the frame of the header view. You need to worry about the position of the label within the header. The VFL for this would be "|titleLabel|" - the title label should be sized to its superview, the header view.