I have new issue related to Auto-Layout world , i can summarize the problem in the below steps:
1- I have storyboard with only one scene contain UIImageView .
2- I went to viewcontroller.m file and add manual constraints like below code
[self.bgImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *horizentalSpaceConstraint = [NSLayoutConstraint constraintWithItem:self.bgImageView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self.view addConstraint:horizentalSpaceConstraint];
Result :
The constraint didn't affect the IBoutlet for UIImageView but if i add UIImageView from hard coded in viewcontroller.m file it works ,can you help me to discover this problem.
I found the solution which can describe by ( Every constraints used IBOutlet elements should before begin add only the below line without need to [setTranslatesAutoresizingMaskIntoConstraints :No]
-(void)viewWillAppear:(BOOL)animated{
// Step 1 remove view constraints for IBOutlet elements
[self.view removeConstraints:self.view.constraints];
}
Related
Here is my problem, I have a scroll view scrollExerciseIndex that I use only as a scrolling bar, in this scroll view I place a UIView indexesView and I want it to be always at the center of the scroll view. For this I use layout constraints :
UIView * indexesView = [[UIView alloc] initWithFrame: CGRectMake(xPosition, 0, dimension*numberIndexes, dimension)];
[self.scrollExerciseIndex addSubview:indexesView];
[self.scrollExerciseIndex setContentSize:CGSizeMake(dimension*numberIndexes, dimension)];
if (xPosition != 0) {
NSLayoutConstraint * xCenterConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.scrollExerciseIndex attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
[self.scrollExerciseIndex addConstraint:xCenterConstraint];
}
Here is the expected result :
Don't pay attention to all the element, just the bar at the bottom of the screen is my problem.
I have to create view programmatically because sometimes I will activate the constraints, sometimes not and I have to set the frame of the view dynamically. So for now I initialise the view indexesView like so :
UIView * indexesView = [[UIView alloc] initWithFrame: CGRectMake(xPosition, 0, dimension*numberIndexes, dimension)];
(I know, not very original)
I would like to know if there is a way to initialize the view programmatically but to say to auto-layout that it has no constraints on the position because right now if the screen turns in landscape mode there is a conflict as the scrollview's frame changes so the distance between the center of the scroll view (on which I set a constraint) and the position of the subview's frame (xPosition) is no longer the same.
As you can see, the view is no longer at the center of the scroll view and I have some constraints broken.
Will attempt to recover by breaking constraint
NSLayoutConstraint:0x7bed6c50 UIView:0x7bed6ad0.centerX == UIScrollView:0x7e273200.centerX
Thanks for your help.
Ok, I found what I was looking for by reading a book about Audio-Layout.
My problem was that audio layout would create constraints behind my back automatically. When using AutoLayout a type of constraints is created from non-autoLayout specifications (The used to describe interface when auto layout didn't exist). So constraints are created using the initial frame of the view. The only thing I had to do was :
[indexesView setTranslatesAutoresizingMaskIntoConstraints:NO];
to disable this creation of constraints from the frame, and then recreate explicitly the constraints for width and height if needed (which wasn't the case for me, but I still made the test) like so :
`NSLayoutConstraint * widthConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:widthValue];
NSLayoutConstraint * heightConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:heightValue];
[indexesView addConstraint: heightConstraint];
[indexesView addConstraint: widthConstraint];`
When adding constraints programmatically, don't forget to call : [indexesView setNeedsUpdateConstraints]; so the constraints are recalculated only when needed.
Last info that I read and can be useful in general, when adding a lot of constraints, the apple doc specifies that it is more efficient to use the method :
[myView addConstraints:(NSArray<NSLayoutConstraints *> *)] than to call addConstraint: for each constraint.
Hope it can be useful to someone.
given the following constraint in ios programmatically:
IBOutlet NSLayoutConstraint *myConstraint;
this constraint is linked in interfacebuilder to the following details:
How do I change the relation attribute programmatically. I tried to look up for a method called setRelation but I don't see it.
According to the documentation, relation is read-only.
What you will need to do, I suspect, is to set
self.myConstraint.active = NO;
Then make a new NSLayoutConstraint programmatically using:
+ constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
And in the process copying values you want to keep, and replacing the relation.
Then add it to the view hierarchy where appropriate.
You can do like that :
[self.view addConstraint:[NSLayoutConstraint
constraintWithItem:self.yellowView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.redView
attribute:NSLayoutAttributeWidth
multiplier:0.75
constant:0.0]];
I have a tableview in my storyboard that has its class set to my UITableView subclass which is named SPSExplanationTableView. There are no constraints set on this tableview in Interface Builder.
I am trying to programmatically create a UIView that displays in front of the tableview—which I know how to do (blog post link)—but that is sized and positioned using Auto Layout. This is my code:
#import "SPSExplanationTableView.h"
#interface SPSExplanationTableView()
#property (nonatomic, strong) UIView *explanationView;
#end
#implementation SPSExplanationTableView
- (void)awakeFromNib
{
[super awakeFromNib];
self.explanationView = [[UIView alloc] init];
self.explanationView.translatesAutoresizingMaskIntoConstraints = NO;
self.explanationView.backgroundColor = [UIColor blueColor];
[self addSubview:self.explanationView];
[self bringSubviewToFront:self.explanationView];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f constant:150.0f];
[self.explanationView addConstraint:heightConstraint];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0f constant:200.0f];
[self.explanationView addConstraint:widthConstraint];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0f constant:0.0f];
[self addConstraint:topConstraint];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.explanationView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0f constant:0.0f];
[self addConstraint:leftConstraint];
#end
When I run the app it crashes with the following assertion failure:
*** Assertion failure in -[SPSExplanationTableView layoutSublayersOfLayer:],
/SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still
required after executing -layoutSubviews. SPSExplanationTableView's
implementation of -layoutSubviews needs to call super.'
Taking the message literally and overriding layoutSubviews has no effect i.e. I still get the same crash.
- (void)layoutSubviews
{
[super layoutSubviews];
}
What's the correct way to implement what I'm trying to achieve?
For Aubada Taljo, here's the tableview in Interface Builder:
Update: I solved this myself in the end by not using Auto Layout! I overrode the layoutSubviews method in my SPSExplanationTableView class and set the center property of the explanationView to the centre of self's bounds, with some slight adjustments to the y-axis position to make it look how I wanted it.
This is crashing because UITableViews are not designed to do this. A UITableView is only concerned about its cells, the headers, maybe its background, and it has logic for this that doesn't use autolayout. So it will crash if you try to involve it in any constraints calculation between it and any subviews, e.g. this will also crash if you add a constraint between the cell and the table.
What I suggest you do is to add a superview that will contain both your table and the view that you want to overlay:
SuperviewWithConstraints
|
|-- YourTableViewWithConstraintsRelativeToSuperview
|
|-- YourOverlayWithConstraintsRelativeToSuperview
And set up the constraints there. Then make that superview as your view controller's view. You will have to move away from using the UITableViewController as the controlling class, though.
If you would take my advice and make your life easier, simply go to your storyboard in Interface Builder and set the correct constraints on the your table view, now go back to the code editor and in the UIViewController that owns your table view, write the view creation code in viewDidLoad e.g.
UIView* someView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, self.tableView.frame.size.height)];
[self.view addSubView someView];
I guess this should be more than enough to solve your issue, now if you face any problems, move your code to viewDidLayoutSubViews in the UIViewController
Please tell me if you need more details but I use this way of creating dynamic controls all the time.
I have a view with 2 container views: one main one on top and one at the bottom.
When the app launches, the bottom one is hidden via a frame that goes beyond the screen height. The top one in the meantime occupies the entire app window.
When I decide to show that bottom container, I want the top container to decrease in height and the view of the controller in that main container to be impacted as well.
I tried to add a constraint programmatically and used layoutIfNeeded but nothing worked.
I'm new to this. I don't necessarily want the best answer but how I should approach this.
Thanks!!!!
-(void)showBottom {
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.bottomContainer attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.mainContainer attribute:NSLayoutAttributeTop multiplier:1.0f constant:49.0f];
[self.view addConstraint:constraint];
}
You can try pinning objects with a Top Space to Superview constraint and animating it.
// .h
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
// .m
[UIView animateWithDuration:1.0 animations:^{
self.topConstraint.constant = 0;
[self.nView layoutIfNeeded];
}];
Since I added the following code, every time my app opens this UITableViewController it crashes:
self.noArticlesView = [[UIView alloc] init];
self.noArticlesView.translatesAutoresizingMaskIntoConstraints = NO;
self.noArticlesView.backgroundColor = [UIColor colorWithRed:0.961 green:0.961 blue:0.961 alpha:1];
[self.view addSubview:self.noArticlesView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.noArticlesView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
And it gives me this error:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'
What on earth am I doing wrong? I call that code in tableView:numberOfRowsInSection: when there's 0 rows.
I was subclassing UIScrollView and received the same error message on iOS 7 (but not 8).
I was overriding layoutSubviews in a manner similar to the following:
- (void)layoutSubviews {
[super layoutSubviews];
// code to scroll the view
}
I resolved the issue by moving the call to super's layoutSubviews to be the last thing in the method:
- (void)layoutSubviews {
// code to scroll the view
[super layoutSubviews];
}
Had the same problem. Added view(s) to self.tableView and used constraints. Do not add the views to the table view via addSubview: but add them as header(s), footer(s) or cells.
[self.view layoutIfNeeded]
Hope this helps
You also need to disable mask translation for the table view.
for me is was this
self.tableView.backgroundView = self.emptyView;
I changed to this
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: #"8.0" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending) {
// OS version >= 8.0
self.tableView.backgroundView = self.emptyView;
}else{
[self.tableView.backgroundView addSubview:self.emptyView];
}
Checkout "Auto Layout still required after executing -layoutSubviews" with UITableViewCell subclass as the question appears to be the same.
I was able to implement the category mentioned in one of the answers which solved the problem for me. However, I had to create the category on the UITableView class instead of the UITableViewCell class as is discussed in that particular answer.
You can add your 'no articles view' as a custom header in the table to make sure it's positioned correctly.
A possible solution is not to add the noArticlesView directly in the table, but is to put the UITableView inside a container UIView (eventually setting table constraints to fit with the container frame) and then constraint your noArticlesView to the container, using the same constraints you set and in the same place in your code, that is inside the -tableView:numberOfRowsInSection: UITableViewDataSource method.
I tested it with a simple example, and it worked.
The changes you need to apply to your code are to replace the UITableViewController with a UIViewController, add a container view (unless you want your table to fit exactly with the view controller's view, in such case this view is the container) and then constraint your noArticleView to the container instead of the table.
My example code is at the bottom of this answer.
I will try to make a possible explanation of the reason of the issue and why this solution works, but consider that part of my explanation is based on guesses so it couldn't be completely exact.
First of all a brief explanation of how the view hierarchy rendering process works in iOS. The first step for the layout engine is to determine the size and position of all views and subviews in the view hierarchy. Usually this is done with an iterative approach, where auto layout constraints are evaluated, in order to determine size and position of views and subviews, and then each view's -layoutSubviews method is called for fine tuning: this means that you can change your layout after constraints are evaluated. What the layout engine requires is that if the -layoutSubviews method changes constraints again, then -[super layoutSubviews] must be called again to allow the iterative process: if this doesn't happen the layout engine raises an exception. In the case of the UITableView my guess is that the tableView:numberOfRowsInSection: method is called somewhere within the internal UITableView layoutSubviews method and this method doesn't call [super layoutSubviews]. So if your table data source method updates internal table constraints, at the end of the method the exception is triggered. The solution I propose works because the only constraint applied to the table is the external constraint towards the container, so evaluated at the first stage of the layout process, while the constraints added in the table data source method are not relevant to the table as they are applied to views external to the table (container and noArticlesView) so they don't affect the internal table view layout process.
//
// RootController.h
#import
#interface RootController : UIViewController
#property (nonatomic,strong) IBOutlet UITableView *table;
#property (nonatomic,strong) IBOutlet UIView *container;
#end
//
// RootController.m
#import "RootController.h"
#implementation RootController
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
UIView *_v = [[UIView alloc] init];
_v.backgroundColor=[UIColor redColor];
_v.translatesAutoresizingMaskIntoConstraints=NO;
[self.container addSubview:_v];
NSLayoutConstraint *_c1 = [NSLayoutConstraint constraintWithItem:_v
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0];
NSLayoutConstraint *_c2 = [NSLayoutConstraint constraintWithItem:_v
attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20.0];
NSLayoutConstraint *_c3 = [NSLayoutConstraint constraintWithItem:_v
attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20.0];
NSLayoutConstraint *_c4 = [NSLayoutConstraint constraintWithItem:_v
attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.container attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20.0];
[self.container addConstraints:#[_c1,_c2,_c3,_c4]];
return 0;
}
I unchecked auto layout on the view controller the crash is not occurring now