How to use Auto Layout to move other views when a view is hidden?
Asked Answered
A

24

367

I have designed my custom Cell in IB, subclassed it and connected my outlets to my custom class. I have three subviews in cell content which are: UIView (cdView) and two labels (titleLabel and emailLabel). Depending on data available for each row, sometimes I want to have UIView and two labels displayed in my cell and sometimes only two labels. What I am trying to do is to set constraints that way if I set UIView property to hidden or I will remove it from superview the two labels will move to the left. I tried to set UIView leading constraint to Superview (Cell content) for 10px and UILabels leading Constraints for 10 px to the next view (UIView). Later in my code

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
    
    // ...

    Record *record = [self.records objectAtIndex:indexPath.row];
    
    if ([record.imageURL is equalToString:@""]) {
         cell.cdView.hidden = YES;
    }
}

I am hiding my cell.cdView and I would like the labels to move to the left however they are staying in the same position in Cell. I tried to remove cell.cdView from superview but it didn't work either. I have attached image to clarify what I am about.

cell

I know how to do this programatically and I am not looking for that solution. What I want is to set constraints in IB and I expect that my subviews will move dynamically if other views are removed or hidden. Is it possible to do this in IB with auto-layout?

.....
Alphabetize answered 5/8, 2013 at 19:16 Comment(3)
Change constraints value runtime - check this answerLoyalist
For this specific case you could also use a UIStackView. when you hide the cd, the labels will occupy their spaceCarpet
@MarcoPappalardo this indeed seems like the only correct solutionLubbi
H
395

It is possible, but you'll have to do a little extra work. There are a couple conceptual things to get out of the way first:

  • Hidden views, even though they don't draw, still participate in Auto Layout and usually retain their frames, leaving other related views in their places.
  • When removing a view from its superview, all related constraints are also removed from that view hierarchy.

In your case, this likely means:

  • If you set your left view to be hidden, the labels stay in place, since that left view is still taking up space (even though it's not visible).
  • If you remove your left view, your labels will probably be left ambiguously constrained, since you no longer have constraints for your labels' left edges.

What you need to do is judiciously over-constrain your labels. Leave your existing constraints (10pts space to the other view) alone, but add another constraint: make your labels' left edges 10pts away from their superview's left edge with a non-required priority (the default high priority will probably work well).

Then, when you want them to move left, remove the left view altogether. The mandatory 10pt constraint to the left view will disappear along with the view it relates to, and you'll be left with just a high-priority constraint that the labels be 10pts away from their superview. On the next layout pass, this should cause them to expand left until they fill the width of the superview but for your spacing around the edges.

One important caveat: if you ever want your left view back in the picture, not only do you have to add it back into the view hierarchy, but you also have to reestablish all its constraints at the same time. This means you need a way to put your 10pt spacing constraint between the view and its labels back whenever that view is shown again.

Handtohand answered 5/8, 2013 at 19:29 Comment(9)
While this answer will certainly work, IMO, over-constraining to handle various use cases seems to be a code smell -- particularly since you would have to re-establish all constraints for any removed views you want to show the view again.Razid
In my opinion, this is not the way to go. You should instead use a width/height-constraint for the view that you want to hide.Ambler
I respectfully disagree. If you (for example) set the view's width to 0, you'll run into two problems. First, you now have double spacing between the superview and the visible view: |-(space)-[hidden(0)]-(space)-[visible] is effectively |-(2*space)-[visible]. Second, that view might start throwing constraint violations depending on its own view subtree and constraints – you can't guarantee that you can arbitrarily constrain a view at 0 width and have it keep working.Handtohand
If you are using a view with intrinsic content size Tim's answer seems the unique way to go.Varicelloid
Thank you Tim. I set a constraint of 0 with a higher priority to avoid constraint incompatibilities, but now I realise there's the problem with the double spacing. I didn't have that problem because I never show the two views together (my case: |-[otherViews]-[eitherThis][orThis]-|), but I'd run into that problem eventually.Rancell
This only worked if a priority of 250 (low) was used. A priority of 750 (high) did not work. Are there any gotchas with using a low priority like 250?Fulgurant
I'm surprised that lowering the priority of the left constraint made it work – if anything, I'd expect a lower priority constraint to take a back seat to other components, like a view's content hugging priority. Consider auditing the other constraints in the system along the same axis as the low-priority constraint and making sure they're all doing what you expect.Handtohand
can we do this programatically using swift?Firebug
Yes – Swift has all the same Auto Layout APIs available as Objective-C does, and the solution I describe can be expressed in terms of those APIs (in a couple different ways, in fact).Handtohand
P
215

Adding or removing constraints during runtime is a heavyweight operation that can affect performance. However, there is a simpler alternative.

For the view you wish to hide, set up a width constraint. Constrain the other views with a leading horizontal gap to that view.

To hide, update the .constant of the width constraint to 0.f. The other views will automatically move left to assume position.

See my other answer here for more details:

How to change label constraints during runtime?

Pteryla answered 6/11, 2013 at 15:16 Comment(11)
The only problem with this solution is that the margin to the left will be the double of what you likely want, so I would update one of those constraints too, but even then I think this is less work than removing the subview.Lengthwise
@skinsfan00atg If you are using a view with intrinsic content size you can't use this solution.Varicelloid
@Varicelloid why not? You could just reduce the content hugging priorityPteryla
@MaxMacLeod If you reduce the content hugging priority then you are not using the intrinsic content size, you are using the size indicated by the constraint.Varicelloid
@Varicelloid reducing the priority says that the content size is less important than the size constraint (in this case 0.f). So the content size will be ignored and the size constraint will be appliedPteryla
@MaxMacLeod Ok, I got what you mean. You need to set the compression resistance priority to 0 (not the content hugging) in code when you want to hide the view, and when you want to show again restore that value. Apart of that you need to add a constraint in interface builder to set the size of the view to 0. There is not need to touch this contraint in the code.Varicelloid
@Varicelloid could you explain in more detail how to use this solution for a view with intrinsic content size?Yeager
Adding textview in a tableview cell does not change the height of the cell. the textview overrides the other views in a cell. I tried adding required constraints but it doesn't helps me.Northeaster
is adding/removing subviews a heavy operation? let's say parentview only has two subviews and only one should be visible at a time: could you just add/remove the two subviews as needed without incurring a performance hit?Fulgurant
I like this answer. I used it with a height constraint. This answer is simple and to the point. +1Schilit
One small note, the constant of an NSLayoutConstraint is of type CGFloat which is a typedef for double (except on Apple Watch where it's a float). So to avoid a messy cast, it's better to set the width constraint to 0.0 than to 0.f.Slattery
S
98

For those who support iOS 8+ only, there is a new boolean property active. It will help to enable only needed constraints dynamically

P.S. Constraint outlet must be strong, not weak

Example:

@IBOutlet weak var optionalView: UIView!
@IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint!
@IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!

func showView() {
    optionalView.isHidden = false
    viewIsVisibleConstraint.isActive = true
    viewIsHiddenConstraint.isActive = false
}

func hideView() {
    optionalView.isHidden = true
    viewIsVisibleConstraint.isActive = false
    viewIsHiddenConstraint.isActive = true
}

Also to fix an error in storyboard you'll need to uncheck Installed checkbox for one of these constraints.

UIStackView (iOS 9+)
One more option is to wrap your views in UIStackView. Once view is hidden UIStackView will update layout automatically

Silassilastic answered 7/5, 2015 at 12:37 Comment(10)
active partly works. But if I use it inside a reusable cell, from activate to deactivate, works, but not for deactivate to activate. Any ideas? Or could you provide a example maybe?Occident
It happens because deactivated constraint is not loaded or deallocated. Your constraint outlet should be strong, not weakSilassilastic
Where can we find that "active" property?Crabbe
developer.apple.com/library/ios/documentation/AppKit/Reference/…Silassilastic
It seems over-constrain + set constraint activity can be the most reasonable answer.Arlettaarlette
I just tried with isActive, but on setting isActive to false the var becomes nil and crashes when setting it to active againKirksey
yes, that is why outlet should not be weak (it is described in P.S.)Silassilastic
Stackview makes wonders. Here's how I did it. Added constraints and tried - didnt work With all constraints existing, selected all views (Vertical only, if you have one row the two horizontal views, first put them into stack view and then include the stack view in selection) Click embed in -> stack view. Connect constraints for the newly created stack view. It magically worksPolyclinic
While IBOutlet is not weak probably you need to set it to nil in func deinit() {}.Stale
StackView is better to manage. Thanks.Desolate
L
91

UIStackView repositions its views automatically when the hidden property is changed on any of its subviews (iOS 9+).

UIView.animateWithDuration(1.0) { () -> Void in
   self.mySubview.hidden = !self.mySubview.hidden
}

Jump to 11:48 in this WWDC video for a demo:

Mysteries of Auto Layout, Part 1

Leveille answered 21/4, 2016 at 12:58 Comment(5)
I hid a nested stack view and the whole containing stack view disappeared.Landry
This should be the accepted answer. Following apple recommandations of wwdc 2015 on interface builder design.Osteitis
@thibautnoah And what about iOS 8- support then?Gilder
@Gilder Unless you're facebook or google you can drop it. With coverage beyong iOS 9 you will support more than 90% of the devices, more than enough. Supporting below will cripple your development process and prevent you from using latest features imoOsteitis
This is the correct answer now. All of the other answers are outdated.Bedtime
D
19

My project uses a custom @IBDesignable subclass of UILabel (to ensure consistency in colour, font, insets etc.) and I have implemented something like the following:

override func intrinsicContentSize() -> CGSize {
    if hidden {
        return CGSizeZero
    } else {
        return super.intrinsicContentSize()
    }
}

This allows the label subclass to take part in Auto Layout, but take no space when hidden.

Dense answered 24/3, 2015 at 13:43 Comment(0)
M
12

For the Googlers: building on Max's answer, to solve the padding issue that many have noticed I simply increased the height of the label and used that height as the separator instead of actual padding. This idea could be expanded for any scenario with containing views.

Here's a simple example:

IB Screenshot

In this case, I map the height of the Author label to an appropriate IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

and when I set the height of the constraint to 0.0f, we preserve the "padding", because the Play button's height allows for it.

Moir answered 30/4, 2014 at 2:30 Comment(1)
For those who are new to NSLayoutConstraint I believe that you want to update the constant property of your authorLabelHeight.Catchpenny
W
9

connect constraint between uiview and labels as IBOutlet and set priority member to a less value when set hidden = YES

Watery answered 6/11, 2013 at 15:11 Comment(2)
You can't adjust the priority of an NSLayoutConstraint once it's established; you have to remove and readd a new constraint with a different priority.Handtohand
I've gotten this method to work. I have a case that uses a label and a button, where I need to hide the button and have the label expand. I have two constraints, one initially with priority 751 and the other with 750. Then when I hide the button, I flip the priorities, and the length of the label grows. It should be noted that if you try to make the higher priority 1000 you get an error "Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported.". So don't and you seem to be fine. Xcode 5.1/viewDidLoad.Slipcover
G
9

Just use UIStackView and everything will be work fine. No need to worry about other constraint, UIStackView will handle the space automatically.

Grievance answered 25/7, 2020 at 12:19 Comment(1)
I would sure be tempted to solve this with nested StackViews as you suggest.Raleighraley
P
8

What I ended up doing was creating 2 xibs. One with the left view and one without it. I registered both in the controller and then decided which to use during cellForRowAtIndexPath.

They use the same UITableViewCell class. The downside is that there is some duplication of the content between the xibs, but these cells are pretty basic. The upside is that I don't have a bunch of code to manually manage removing view, updating constraints, etc.

In general, this is probably a better solution since they are technically different layouts and therefore should have different xibs.

[self.table registerNib:[UINib nibWithNibName:@"TrackCell" bundle:nil] forCellReuseIdentifier:@"TrackCell"];
[self.table registerNib:[UINib nibWithNibName:@"TrackCellNoImage" bundle:nil] forCellReuseIdentifier:@"TrackCellNoImage"];

TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:(appDelegate.showImages ? @"TrackCell" : @"TrackCellNoImage") forIndexPath:indexPath];
Philately answered 5/12, 2014 at 22:29 Comment(0)
F
7

In this case, I map the height of the Author label to an appropriate IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

and when I set the height of the constraint to 0.0f, we preserve the "padding", because the Play button's height allows for it.

cell.authorLabelHeight.constant = 0;

enter image description here enter image description here

Francesfrancesca answered 1/12, 2015 at 7:56 Comment(0)
E
7

For this specific layout the constraint to be working with is the 'leading' constraint on the view that is being hidden. The below theory will work in all directions though.

1: Setup all your constraints how you want it to look when all views are visible.

2: Add a second 'leading' constraint to the view you want to hide. This will break the constraints for a moment.

3: Change the priority of the original leading constraint to be '999' - this then gives priority to your new constraint which will be at 1000 and no constraints will be broken anymore.

4: Change the new constraint from 'leading=leading' to be 'trailing=leading'. This will move the view you want to hide off the leading edge of its parent shifting it out of the way.

5: Toggling the new constraint's isActive value will now toggle if it's in the view or outside it. Set that to true/false at the same time as setting the visibility to true/false. Eg:

@IBOutlet var avatar:UIImage!
@IBOutlet var avatarLeadHid:NSLayoutConstraint!

func hideAvatar() {
  self.avatar.isHidden = true
  self.avatarLeadHid.isActive = true
}

func showAvatar() {
  self.avatar.isHidden = false
  self.avatarLeadHid.isActive = false
}

Bonus: You can adjust the 'constant' value of the new hider-constraint in order to alter the padding/margin to use when the view is hidden. This value can be negative.

Extra Bonus: It's possible to see what your layout will look like from within the Interface Builder without running any code just by toggling the 'Installed' checkbox on the hider-constraint.

Further Help: I made a video that shows what I do better that a list of points: https://youtu.be/3tGEwqtQ-iU

Emilieemiline answered 16/4, 2021 at 15:12 Comment(1)
A lot of times it looks better to animate the constraint, so rather than suddenly changing the value of the constraint or deactivating it, set your offset value for the layoutConstraint, and then animate the transition from the constraint's previousconstant value to the new value with: UIView.animate(widthDuration: n) { view.layoutIfNeeded() }. Plenty of examples: https://mcmap.net/q/93551/-animate-subview-autolayout-constraint-changesRaleighraley
N
6

Use two UIStackView Horizontal and Vertical, when some subview view in stack is hidden other stack subviews will be moved, use Distribution -> Fill Proporionally for Vertical stack with two UILabels and need set width and height constaints for first UIViewenter image description here

Nucleus answered 5/4, 2017 at 15:32 Comment(0)
K
2

In my case I set the constant of the height constraint to 0.0f and also set the hidden property to YES.

To show the view (with the subviews) again I did the opposite: I set the height constant to a non-zero value and set the hidden property to NO.

Kisser answered 11/6, 2015 at 13:8 Comment(0)
L
2

Try this,I have implemented below code ,

I have one View on ViewController in that added other three views, When any view is hidden other two view will move,Follow below steps. ,

1.ViewController.h File

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *viewOne;
@property (strong, nonatomic) IBOutlet UIView *viewTwo;
@property (strong, nonatomic) IBOutlet UIView *viewThree;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewOneWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewTwoWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewThreeWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewBottomWidth;
@end

2.ViewController.m

 #import "ViewController.h"
 @interface ViewController ()
{
  CGFloat viewOneWidthConstant;
  CGFloat viewTwoWidthConstant;
  CGFloat viewThreeWidthConstant;
  CGFloat viewBottomWidthConstant;
}
@end

@implementation ViewController
@synthesize viewOne, viewTwo, viewThree;

- (void)viewDidLoad {
  [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a 
  nib.

  /*
   0  0   0
   0  0   1
   0  1   0
   0  1   1
   1  0   0
   1  0   1
   1  1   0
   1  1   1
   */

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:YES];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:YES];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:NO];
  //    [viewTwo setHidden:YES];
  //    [viewThree setHidden:YES];


  //    [viewOne setHidden:YES];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:NO];

  //    [viewOne setHidden:YES];
  //    [viewTwo setHidden:NO];
  //    [viewThree setHidden:YES];

 //    [viewOne setHidden:YES];
 //    [viewTwo setHidden:YES];
 //    [viewThree setHidden:NO];

//    [viewOne setHidden:YES];
//    [viewTwo setHidden:YES];
//    [viewThree setHidden:YES];

 [self hideShowBottomBar];
  }

- (void)hideShowBottomBar
{
  BOOL isOne = !viewOne.isHidden;
  BOOL isTwo = !viewTwo.isHidden;
  BOOL isThree = !viewThree.isHidden;

  viewOneWidthConstant = _viewOneWidth.constant;
  viewTwoWidthConstant = _viewTwoWidth.constant;
  viewThreeWidthConstant = _viewThreeWidth.constant;
  viewBottomWidthConstant = _viewBottomWidth.constant;

   if (isOne && isTwo && isThree) {
    // 0    0   0
    _viewOneWidth.constant = viewBottomWidthConstant / 3;
    _viewTwoWidth.constant = viewBottomWidthConstant / 3;
    _viewThreeWidth.constant = viewBottomWidthConstant / 3;
    }
    else if (isOne && isTwo && !isThree) {
     // 0    0   1
    _viewOneWidth.constant = viewBottomWidthConstant / 2;
    _viewTwoWidth.constant = viewBottomWidthConstant / 2;
    _viewThreeWidth.constant = 0;
    }
   else if (isOne && !isTwo && isThree) {
    // 0    1   0
    _viewOneWidth.constant = viewBottomWidthConstant / 2;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = viewBottomWidthConstant / 2;
    }
    else if (isOne && !isTwo && !isThree) {
    // 0    1   1
    _viewOneWidth.constant = viewBottomWidthConstant;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = 0;
   }
   else if (!isOne && isTwo && isThree) {
    // 1    0   0
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = viewBottomWidthConstant / 2;
    _viewThreeWidth.constant = viewBottomWidthConstant / 2;
   }
   else if (!isOne && isTwo && !isThree) {
    // 1    0   1
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = viewBottomWidthConstant;
    _viewThreeWidth.constant = 0;
   }
   else if (!isOne && !isTwo && isThree) {
    // 1    1   0
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = viewBottomWidthConstant;
   }
   else if (isOne && isTwo && isThree) {
    // 1    1   1
    _viewOneWidth.constant = 0;
    _viewTwoWidth.constant = 0;
    _viewThreeWidth.constant = 0;
   }
  }

 - (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
 // Dispose of any resources that can be recreated.
 }
 @end

enter image description here enter image description here enter image description here

Hope So this logic will help some one.

Libnah answered 8/2, 2018 at 11:31 Comment(0)
U
2

I will use horizontal stackview. It can remove the frame when the subview is hidden.

In image below, the red view is the actual container for your content and has 10pt trailing space to orange superview (ShowHideView), then just connect ShowHideView to IBOutlet and show/hide/remove it programatically.

  1. This is when the view is visible/installed.

view is visible

  1. This is when the view is hidden/not-installed.

view is hidden/removed

Unrealizable answered 5/3, 2018 at 9:45 Comment(0)
U
1

This my another solution using priority constraint. The idea is set the width to 0.

  1. create container view (orange) and set width. enter image description here

  2. create content view (red) and set trailing space 10pt to superview (orange). Notice trailing space constraints, there are 2 trailing constraint with different priority. Low(=10) and High(<=10). This is important to avoid ambiguity. enter image description here

  3. Set orange view's width to 0 to hide the view. enter image description here

Unrealizable answered 5/3, 2018 at 10:3 Comment(0)
M
1

The easiest solution is to use UIStackView (horizontal). Add to stack view: first view and second view with labels. Then set isHidden property of first view to false. All constrains will be calculated and updates automatically.

Meeting answered 9/1, 2020 at 20:39 Comment(0)
C
1

Instead of hiding view, create the width constrain and change it to 0 in code when you want to hide the UIView.

It may be the simplest way to do so. Also, it will preserve the view and you don't need to recreate it if you want to show it again (ideal to use inside table cells). To change the constant value you need to create a constant reference outlet (the same way as you do outlets for the view).

Cephalo answered 24/8, 2020 at 11:57 Comment(1)
This sir was the easiest solution for this. As long as you have a height or width constraint, this works well.Dolores
F
0

As no_scene suggested, you can definitely do this by changing the priority of the constraint at runtime. This was much easier for me because I had more than one blocking view which would have to be removed.

Here's a snippet using ReactiveCocoa:

RACSignal* isViewOneHiddenSignal = RACObserve(self.viewModel, isViewOneHidden);
RACSignal* isViewTwoHiddenSignal = RACObserve(self.viewModel, isViewTwoHidden);
RACSignal* isViewThreeHiddenSignal = RACObserve(self.viewModel, isViewThreeHidden);
RAC(self.viewOne, hidden) = isViewOneHiddenSignal;
RAC(self.viewTwo, hidden) = isViewTwoHiddenSignal;
RAC(self.viewThree, hidden) = isViewThreeHiddenSignal;

RAC(self.viewFourBottomConstraint, priority) = [[[[RACSignal
    combineLatest:@[isViewOneHiddenSignal,
                    isViewTwoHiddenSignal,
                    isViewThreeHiddenSignal]]
    and]
    distinctUntilChanged]
    map:^id(NSNumber* allAreHidden) {
        return [allAreHidden boolValue] ? @(780) : @(UILayoutPriorityDefaultHigh);
    }];

RACSignal* updateFramesSignal = [RACObserve(self.viewFourBottomConstraint, priority) distinctUntilChanged];
[updateFramesSignal
    subscribeNext:^(id x) {
        @strongify(self);
        [self.view setNeedsUpdateConstraints];
        [UIView animateWithDuration:0.3 animations:^{
            [self.view layoutIfNeeded];
        }];
    }];
Foxglove answered 10/3, 2015 at 7:51 Comment(0)
R
0

In case this helps someone, I built a helper class for using visual format constraints. I'm using it in my current app.

AutolayoutHelper

It might be a bit tailored to my needs, but you might find it useful or you might want to modify it and create your own helper.

I have to thank Tim for his answer above, this answer about UIScrollView and also this tutorial.

Rancell answered 9/4, 2015 at 0:56 Comment(0)
O
0

Here's how I would re-align my uiviews to get your solution:

  1. Drag drop one UIImageView and place it to the left.
  2. Drag drop one UIView and place it to the right of UIImageView.
  3. Drag drop two UILabels inside that UIView whose leading and trailing constraints are zero.
  4. Set the leading constraint of UIView containing 2 labels to superview instead of UIImagView.
  5. IF UIImageView is hidden, set the leading constraint constant to 10 px to superview. ELSE, set the leading constraint constant to 10 px + UIImageView.width + 10 px.

I created a thumb rule of my own. Whenever you have to hide / show any uiview whose constraints might be affected, add all the affected / dependent subviews inside a uiview and update its leading / trailing / top / bottom constraint constant programmatically.

Our answered 12/7, 2017 at 14:24 Comment(0)
F
0

This is an old question but still I hope it will helps. Coming from Android, in this platform you have an handy method isVisible to hide it from the view but also not have the frame considered when the autolayout draw the view.

using extension and "extend" uiview you could do a similar function in ios (not sure why it is not in UIKit already) here an implementation in swift 3:

    func isVisible(_ isVisible: Bool) {
        self.isHidden = !isVisible
        self.translatesAutoresizingMaskIntoConstraints = isVisible
        if isVisible { //if visible we remove the hight constraint 
            if let constraint = (self.constraints.filter{$0.firstAttribute == .height}.first){
                self.removeConstraint(constraint)
            }
        } else { //if not visible we add a constraint to force the view to have a hight set to 0
            let height = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 0)
            self.addConstraint(height)
        }
        self.layoutIfNeeded()
    }
Filum answered 23/10, 2017 at 16:15 Comment(0)
P
0

the proper way to do it is to disable constraints with isActive = false. note however that deactivating a constraint removes and releases it, so you have to have strong outlets for them.

Provenance answered 6/2, 2018 at 13:15 Comment(0)
S
0

I think this is the most simple answer. Please verify that it works:

        StackFullView.layer.isHidden = true
        Task_TopSpaceSections.constant = 0.   //your constraint of top view

check here https://www.youtube.com/watch?v=EBulMWMoFuw

Squarerigger answered 26/12, 2018 at 7:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.