How to set constraints programmatically for a varying number of UIView - ios

I'm new to auto layout constraints. In my application there are 3 buttons in one line. Now I want to set the constraints programatically as shown in the image below:
If there is one, then the button show in center horizontally.
If two buttons are enable, then second line shown in same image as three image.

My approach is to setting all buttons centerX to superview's centerX at the beginning.
IBOutletCollection(UIButton) NSArray *allButtons;
//3 buttons' references
IBOutletCollection(NSLayoutConstraint) NSArray *allButtonCenterConstraints;
//buttons' centerX constraints' references
and then if in viewDidAppear:
int t = arc4random() %3;// one of the 3 cases you will need
if (t == 0) {//if you want all 3 buttons appears
//all buttons shown
NSLayoutConstraint *c1 = allButtonCenterConstraints[0];//first button's centerX reference.
NSLayoutConstraint *c2 = allButtonCenterConstraints[2];//third button's centerX reference.
c1.constant = -self.view.frame.size.width*0.25;//push left
c2.constant = +self.view.frame.size.width*0.25;//push right
}
else if (t == 1)
{
//two buttons shown;
[allButtons[0] setHidden:YES];// close the one you dont need
NSLayoutConstraint *c1 = allButtonCenterConstraints[1];
NSLayoutConstraint *c2 = allButtonCenterConstraints[2];
c1.constant = -self.view.frame.size.width*0.125;
c2.constant = +self.view.frame.size.width*0.125;
}
else
{
//close 2 buttons
[allButtons[0] setHidden:YES];
[allButtons[1] setHidden:YES];
}
[self.view layoutIfNeeded];
if you need something depends on the width of buttons, you can set the constants according to the width of buttons.

Make constraint outlet after that you set constraint pragmatically
like as :
#IBOutlet var mainViewWidthConstant: NSLayoutConstraint!
if (self.view.frame.size.width == 320){
mainViewWidthConstant.constant = 320
}
else if (self.view.frame.size.width == 375)
{
mainViewWidthConstant.constant = 375
}
else{
mainViewWidthConstant.constant = 414
}

Related

Read CGFloat from Anchor Constraints

I created an UIView and then added the Anchor constraints but I have a problem when I want to read the values ...
In this case as you see, I created an NSLayoutConstraint property to get the Anchor Width of my uiview ... I then created a CGFloat that contains constraint but my NSLog always returns me a ZERO value.
where am I wrong? how can I get the width values of my UIView assigned to the Anchors?
UIView *trackLine = [[UIView alloc] init];
trackLine.backgroundColor = [self trackLineColor];
trackLine.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:trackLine];
[trackLine.topAnchor constraintEqualToAnchor:mediaTitle.bottomAnchor constant:25].active = YES;
[trackLine.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[trackLine.heightAnchor constraintEqualToConstant:1].active = YES;
self.width = [trackLine.widthAnchor constraintEqualToAnchor:self.widthAnchor multiplier:.8];
self.width.active = YES;
CGFloat trackLineLenght = self.width.constant;
NSLog(#"TRACK LINE %f", trackLineLenght );
NSLog Result:
**2017-10-21 17:10:35.096562+0200 [5501:1994879] TRACK LINE 0.000000**
OK - a little confusion...
First, don't use "width" as a property name... very confusing, since width is used in so many places already.
So, let's assume you have:
#property NSLayoutConstraint *trackLineWidthConstraint;
A .widthAnchor doesn't really have a width in terms of "what's the width of the anchor." The way you are defining your constraints:
self.trackLineWidthConstraint = [trackLine.widthAnchor constraintEqualToAnchor:self.widthAnchor multiplier:.8];
Says "set the .trackLineWidthConstraint property to 80% of the width of self. So, whenever the actual width of self changes, the actual width of your trackLine view will change to 80% of the new width.
The .constant is Zero. If it was something other than zero, that value would be added after calculating 80%. For example:
self.trackLineWidthConstraint = [trackLine.widthAnchor constraintEqualToAnchor:self.widthAnchor multiplier:.8];
// if self is 200-pts wide, trackLine will be 160-pts
self.trackLineWidthConstraint.constant = 10
// trackLine width is now (200 * 0.8) + 10, or 170-pts
If you want to get the current width of trackLine, you can get it from its .frame (after auto-layout has finished).
Hopefully, that didn't just make it more confusing :)

UIView subview autolayout issue

I have UITableView Cell in which 4 UIViews are arranged in a vertical order like this,
In each UIView, I have two Labels like this,
I have taken a IBOutlet for Height Constraint of all of the Four UIViews and I want to make the height 0 of the view when data is not available in that view. The problem is View is not getting 0 height due to the 10 px bottom constraint of UILabel inside that View.
What i am getting is like this,
Code where constraints are handled
NSString *toName = [self jointNameFromArray:evidence.arrTo];
if ([Utility isEmptyString:toName]) {
cell.toViewHeight.constant = 0;
}
else {
cell.lblToName.text = toName;
}
NSString *fromName = [self jointNameFromArray:evidence.arrFrom];
if ([Utility isEmptyString:fromName]) {
cell.fromViewHeight.constant = 0;
}
else {
cell.lblFromName.text = fromName;
}
NSString *ccName = [self jointNameFromArray:evidence.arrCc];
if ([Utility isEmptyString:ccName]) {
cell.ccViewHeight.constant = 0;
}
else {
cell.lblCCName.text = ccName;
}
NSString *custName = [self jointNameFromArray:evidence.arrCustodian];
if ([Utility isEmptyString:custName]) {
cell.custViewHeight.constant = 0;
}
else {
cell.lblCustName.text = custName;
}
[cell layoutIfNeeded];
If you're targeting iOS 9+, I'd suggesting using UIStackView, as it does exactly what you want just by setting the .hidden property of your view to true.
https://www.raizlabs.com/dev/2016/04/uistackview/
If you are unable to use UIStackView, you will need to set one of the vertical padding constraints to a lower priority than the height constraint. You will also need to set .clipsToBounds to true.
Set constraint programatically and write logic as u want it is good idea and dont forgot to set layoutifnedded.

Why i can't move image and set text in label at the same time

I want to move background to the left like my character is walking and show number of walking but it can't do that at the same time. this method leftfootButton can only set text in label
- (IBAction)leftfootButton:(id)sender {
_bgGround.center = CGPointMake(_bgGround.center.x -50, _bgGround.center.y);
i = i+1;
self.show.text = [NSString stringWithFormat:#"%d",i];
}
If i comment the code that sets the text out then it can move background
- (IBAction)rightfootButton:(id)sender {
_bgGround.center = CGPointMake(_bgGround.center.x - 50, _bgGround.center.y);
i = i+1;
//self.show.text = [NSString stringWithFormat:#"%d",i];
}
what should i do?
You should not change frames directly when you use auto layout because layoutSubviews method will return frames to their previous position. This method is called by system in many cases. You could override it to set the frame rectangles of your subviews directly. But I recommend you to change constraints of your background view. Even if you did not set constraints to your views, they was added automatically.
When you use Layout Constraint then you should never change the frame, you should try to change the constraint, e.g.
Create a IBOutlet for x contraint for the view like below, make sure it's correctly connected.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *xContraint;
Then in your action
- (IBAction)leftfootButton:(id)sender {
self.xContraint.constant -= 50;
i = i + 1;
self.show.text = [NSString stringWithFormat:#"%d", i];
}

iOS autolayout with resize

I have two views one is textView and below it is a scrollview, in my application the textView should toggle expand when touch it.I set the "Top Space to: Text View" for scrollView in IB.But When I expand the textView it seems not work.
here is the toggle expand code.
- (void)onTextViewClicked:(id)sender
{
CGRect targetFrame = _descTextView.frame;
if (_isTextViewExpand) {
targetFrame.size.height = _descTextViewNormalHeight;
_descTextView.frame = targetFrame;
_isTextViewExpand = NO;
[_contentScrollView setContentSize:CGSizeMake(320.f, kContentScrollViewDefaultHeight)];
}
else {
targetFrame.size.height = _descTextViewExpandHeight;
_descTextView.frame = targetFrame;
_isTextViewExpand = YES;
[_contentScrollView setContentSize:CGSizeMake(320.f, kContentScrollViewDefaultHeight + ( _descTextViewExpandHeight - _descTextViewNormalHeight ))];
}
}
You need a different approach entirely. With Auto Layout, you should never call -setFrame:. If you want the views to grow you should add a constraint or edit one of the existing constraints and then call either -setNeedsUpdateConstraints or -layoutIfNeeded.
Or just turn off Auto Layout.

Split the full contents of cell between UILabel and UIButton

I've got a subclassed UITableViewCell. I'm dynamically adding a UILabel and UIButton to it.
Right now I've overridden layoutSubviews and am setting the x,y absolutely of the button and label. To be able to accommodate both screen layouts as well as larger screens I'd like to make this automatic. Is there a way to tell the label to "float left" and the button to "float right?" Ideally the label should use up all space that the button doesn't need (the button is going to be a fixed size for the most part).
this property of uiview should get you started
You can try something like this assuming cellLbl is the UILabel and cellBtn is the UIButton:
- (void) layoutSubviews
{
CGRect rctFrm;
CGFloat flW;
CGFloat flH;
int iSpacing = 4; // This could be fixed for a percentage of cell width
[super layoutSubviews];
flW = self.contentView.bounds.size.width;
flH = self.contentView.bounds.size.height;
rctFrm = self.cellBtn.frame;
flW -= rctFrm.size.width + iSpacing;
rctFrm.origin.x = flW; // Right justify button
rctFrm.origin.y = (flH - rctFrm.size.height) / 2; // Center button vertically
[self.cellBtn setFrame:rctFrm];
rctFrm = self.cellLbl.frame;
rctFrm.origin.x = iSpacing;
rctFrm.size.width = flW - (2 * iSpacing);
// You can adjust UILabel vertical position and height if desired
[self.cellLbl setFrame:rctFrm];
}

Resources