updating constraint value not working in auto layout - ios

I have created the IBOutlet for the constraint of top spacing . I need to update the value that constraint programatically in viewDidLoad. Here is my declaration in IBOutlet :
IBOutlet NSLayoutConstraint *labelTopSpace;
and here is how I changing the top:
labelTopSpace.constant = 50.0;
but this is not working in my case . am I missing anything ?
Update : should I make the property of it ?

Hope, you have mentioned all the constraints under method!
- (void)updateViewConstraints
{
[super updateViewConstraints];
_labelTopSpace.constant = 50;
}

Try using below code..
[btn setConstraintConstant:50.0 forAttribute:NSLayoutAttributeTop];
you can replace the btn with any Ref which for which you have that Constraint that need to modified.{say self.view//if it is for view}
In this case you no need to create property or IBOulet reference to your Constraint..
You can Directly change as above..
Hope it is useful to you as alternate solution...!

Make it property, like
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelTopSpace;
then check outlet connection. similarly asked question Unable to make outlet connection to a constraint in IB

Related

How to set hide and show view using constraints like auto layout /StackView

I have a larger screen to design, it had plus button, for adding more fields in it. For example, i need to add 2 Email/Phone number, when i press plus button it will show one more textfield with in Email header as vice versa. If i use hide and show method programmatically, the rest of the space will be blank. For this i need to set constraint and setLayout for view. How is it possible?
I would like to give idea so quick look at it.
Take a scroll view inside take one view that having all field your textfield like email and more text that you want.
Now design all field whatever you have to show.
add
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *ViewHeightConstraints;
for container view when you hide textfield just subtract height of all hideTextfield to ViewHeightConstraints.
ok when you hide textfield do something like this:
ViewHeightConstraints.constant = 0;
_addressView.hidden = YES;
[self.view layoutIfNeeded];
ok when you Show textfield do something like this:
ViewHeightConstraints.constant = 243;
_addressView.hidden = NO;
[self.view layoutIfNeeded];
whenever you change constraints write this Everytime.
[self.view layoutIfNeeded];
for setting frame for your main View Set height constraints for MainView. i have done like this.
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *containerHeightConstraints;
_containerHeightConstraints.constant = _bottomView.frame.origin.y+_bottomViewHeight.constant;
[self.view layoutIfNeeded];
Hope it will work.
You need to take a IBOutlet of the field height constraint for this.
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *fieldConstraintHeight;
Now when you want to hide it use
fieldConstraintHeight.constant = 0;

UIProgressView have different position at runtime

I place a UIProgressView on an XIB file. At first it goes well. After when I set its height via auto layout to be 20, problem occurred. The Progress View always got its position at the most top-left of the screen. even I use
[self.progress setFrame:CGRectMake(93, 100, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
still don't work for me at all.
Thank you very much for any help.
use size constraints as outlets. Then you can easy change values of those constraints. It's not really recommended to modify frame when using auto-layout.
declare a property:
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *widthConstraint;
and in the implementation:
self.heightConstraint = self.scrollView.frame.size.height;
self.widthConstraint= self.scrollView.frame.size.width;
Alternatively you can try to set frame in viewDidLayoutSubviews but it's not recommended when using auto-layout.

Can't change Constraint IBOutlet that is defined for different size classes in IB

I made a special test app for this case. (I'm sorry it is already removed)
I added a view on my controller's view in Storyboard, set up AutoLayout constraints in Interface Builder and made one of them (vertical space) is defferent for different size classes. Screenshot from IB
So the value is 100 for Any height, Any width and 0 for Regular height, Regular width.
It works well, on iPhone vertical distance from top is 100, when on iPad it is 0.
Also I made IBOutlet for this constraint and want to change it in runtime to 10
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
it seemed I couldn't change it because it gives no effect
- (void)viewDidLoad
{
[super viewDidLoad];
self.topVerticalConstraint.constant = 10; // it doesn't work
}
Although it works when I remove value for Regular height, Regular width in Interface Builder.
Am I miss something about the size classes?
The problem is that constraints are not fully defined yet until Layout events happen between -viewWillLayoutSubviews and -viewDidLayoutSubviews where all the parameters from IB comes into play.
My rule of thumb is:
if you use frames to position your views manually you can do it as early as -viewDidLoad,
if you use autolayout constraints for positioning, make adjustments as early as -viewDidLayoutSubviews;
The second statements only considers code adjustments to constraints that have been made in IB. Adjustments that you are making in -viewDidLoad will be overridden by parameters set in IB during layout. If you add constraints with code you can set them in -viewDidLoad, since there will be nothing to override them.
I've changed your code a bit and it works:
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
#property (weak, nonatomic) IBOutlet UIView *square;
#property (assign, nonatomic) BOOL firstLayout;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstLayout = YES;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.firstLayout) {
self.topVerticalConstraint.constant = 10;
self.firstLayout = NO;
}
}
#end
Notice that -viewDidLayoutSubviews is called many times during the lifetime of a ViewController, so you have to make sure that your adjustments happen only once on initial load.
The problem:
If you set up different value for different size classes in IB for the constraint like this:
then you can't change constant value in code like this:
self.adHeightConstraint.constant = 0; // value set to 0
[self.view layoutIfNeeded]; // value get back to IB value (44 or 36)
In this situation you may see that your constant value persists only until views recalculates. So, after [self.view layoutIfNeeded] the value of constant reset back to whatever was set in IB.
The solution:
Add the second constraint of the same attribute (in my case it was the height) with desired value. You may set this value in IB or change it in the code.
Set low priority for this new constraint. Since it's low priority, it won't be any conflict.
Now when you need to apply the new constant, simple disable the first constraint:
self.adHeightConstraint.active = NO;
[self.view layoutIfNeeded];
I have experienced the same issue, but it doesn't seem to have anything to do with viewDidLoad vs viewDidLayoutSubviews. Interface Builder can manage alternate constraint constants for different size classes, but when you try to update NSLayoutConstraint.constant in code, that constant isn't associated with any particular size class (including the active one).
From Apple docs, Changing Constraint Constants for a Size Class (XCode 7, Interface Builder)
My solution has been to remove the alternate constants from IB, and manage the size-based constraint constant switch in code, only for those specific constraints that are updated/modified in code. Any constraints that are only managed via storyboard/IB can use the alternate-size constants as normal.
// XCode 7.0.1, Swift 2.0
static var isCompactHeight : Bool = false;
static var heightOffset : CGFloat {
return (isCompactHeight ? compactHeightOffset : regularHeightOffset);
}
/* applyTheme can be called as early as viewDidLoad */
func applyTheme() {
// This part could go wherever you handle orientation changes
let appDelegate = UIApplication.sharedApplication().delegate;
let window = appDelegate?.window;
let verticalSizeClass = window??.traitCollection.verticalSizeClass ?? UIUserInterfaceSizeClass.Unspecified;
isCompactHeight = (verticalSizeClass == UIUserInterfaceSizeClass.Compact);
// Use heightOffset
changingConstraint.constant = heightOffset;
}
I'm hoping that some later version of Swift/XCode introduces getters & setters that take size-based alternates into account, mirroring the functionality that's already available via IB.
I check same scenario in sample project it was working may be you are forget to connect NSLayoutConstraint topVerticalConstraint with storyboard.
Change constraint's constant in viewDidLayoutSubviews
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (IS_IPHONE4) {
self.topConstraint.constant = 10;
self.bottomButtonTop.constant = 10;
self.pageControlTopConstraint.constant = 5;
}
}
Easiest solution:
if (self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
// for iPhone
cnicTopConstraint.constant = -60;
} else {
// for iPad
cnicTopConstraint.constant = -120;
}

changing UITableView position programatically with AutoLayout support

I want to change position of UITableview position programmatically. I have added following code in viewDidLoad,ViewWillAppear callbacks, but position is not changing.
Table.frame = CGRectMake(0,100,320,200);
When I disable Auto Layout option in Storyboard, Table View's position is changing. But, I need to keep Auto Layout option to maintain support for different device type.
Use autolayout, and set constraints to your tableView's position & size.
Then, create IBOutlet instances of the type NSLayoutConstraint, and attach them to your constraints in the xib.
Then, in your code, set the values of the constraints to reset the table view position.
Sample code:
in your .h file:
#property IBOutlet NSLayoutConstraint *tableOriginX;
#property IBOutlet NSLayoutConstraint *tableOriginY;
#property IBOutlet NSLayoutConstraint *tableWidth;
#property IBOutlet NSLayoutConstraint *tableHeight;
Then, in your .m file where you want to alter your table's frame:
tableOriginX.constant = 0;
tableOriginY.constant = 100;
tableWidth.constant = 320;
tableHeight.constant = 200;

Change frame programmatically with auto layout

I have a UITableView with Auto Layout and I need to reduce the height when the GADBannerView appears at the bottom of the screen.
Unfortunately with Auto Layout it is impossible to modify the frame. The solution is to remove Auto Layout and set the frame manually. This is very dangerous because all my apps works fine on 3.5' and 4.0' displays and removing Auto Layout adds a new testing phase and more effort.
Is there a way to change the frame even if Auto Layout is enabled?
Let your UITableView constraints to bottom layout is set to 0, make an IBOutlet. Now let your GADBannerView height is 40 so change your outlet.constant = 40; For more about how to make IBOutlet and change its value have a look into this or this hope this will help.
Edit: For those who seeking for example, follow these simple steps (Because this is accepted answer, I think it is worth to have an example. Credit to #manujmv for this example)
Create a height constraint for your view in your interface.
Then add an IBOutlet object in your class for this constraint.
For example:
#property (weak, nonatomic) IBOutlet NSLayoutConstraint
*heightConstraint;
Connect this object in your connection panel.
Then change the value of this constraint whenever you needed
self.heightConstraint.constant = 40;
Rather than trying to change the frame of the view, add a height constraint using auto layout and reduce the value of this constraint. Do the below steps:
create a height constarint for your view in your interface.
Then add an IBOutlet object in your class for this constraint. for example,
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
Connect this object in your connection panel.
Then change the value of this constraint whenever you needed
self.heightConstraint.constant = 40;
One more thing, you have to call [self.view layoutIfNeeded]; method once you changne the constraints.
Enjoy :)
You can find out constraint like that
extension UIView {
var heightConstaint: NSLayoutConstraint? {
get {
for constraint: NSLayoutConstraint in constraints {
if constraint.firstAttribute == .height {
if constraint.relation == .equal {
return constraint
}
}
}
return nil
}
set{
setNeedsLayout()
}
}
}

Resources