iOS equivalent for Android View.GONE visibility mode
Asked Answered
S

13

80

I'm developing an app for iOS and I'm using the Storyboard with AutoLayout ON. One of my view controllers has a set of 4 buttons, and in certain circumstances i would like to make the first one disappear.

If I use the setHidden:TRUE method the UIButton become invisible but it still obviously take space in the view, and the result is an "hole" which I've not been able to fill making the remaining UIButton to float towards the top of the main view.

In Android I would have simply used View.GONE instead of View.INVISIBLE, but in iOS I'm stuck with this behaviour and I don't want to believe that the only solution is to manually (yes I mean programmatically) move the remaining elements to the top.

I thought I would have been able to do it setting some sort of Constraint to make everything as automatic as it is in Android but I've had no luck.

Before I turn Autolayout OFF, can someone point me to the right direction?

I'm using the IB, but I'm comfortable with programmatic stuff as well.

UPDATE:

Setting the component height to 0 doesn't help as well.

I tried something like this:

UIButton *b;
CGRect frameRect = b.frame;
frameRect.size.height = 0;
b.frame = frameRect;
Scheldt answered 25/7, 2013 at 21:41 Comment(3)
How about setting the height of the button to zero?Invariable
I tried something like this: UIButton * b; CGRect frameRect = b.frame; frameRect.size.height = 0; b.frame = frameRect; No luck :(Scheldt
I know this is a super old question but regarding your update setting the frame to 0 won't help if you're using autolayout. You have to set the height constraint to 0Corticate
L
41

Adding a constraint(NSLayoutAttributeHeight) that sets height of the view to 0 worked for me:

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captchaView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0]];
Lipase answered 26/3, 2014 at 19:6 Comment(10)
Swift version: self.view.addConstraint(NSLayoutConstraint(item: self.captchaView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0))Invocate
This should have been the answerPlenteous
What if I don't know actual height of desired view (for ex. container view rendered little bit later)?Saltandpepper
Thanks a lot for the awesome answer! For someone may need it. I got an error Unable to simultaneously satisfy constraints. while I already had a constraints for the view. I solve it by https://mcmap.net/q/261015/-ios-controls-hide-and-gone-like-androidAntilogism
@Invocate i have used same code but it doesn't work ...#45455492Heida
@Lipase i have used same code but it doesn't work ...#45455492Heida
Awesome answer.Saved my dayWove
but you may have some padding, spacing for this viewVascular
p.s. constant height sucks, I use equal height and multiplier, for example to take 25% of parent view, any example for it?Vascular
Usually I'd use UIStackView, but this works best for cases in which you have to push your views to one side of the container view instead of distributing their spacing. Great alternative answer.Proximate
H
21

All of answers on this questions are inefficient. Best way to equvailent of Android setVisibility:Gone method on iOS is that StackView first select components then in editor, embed in, Stack View,

connect new stack view with IBOutlet, then:

hidden:

UIView * firstView = self.svViewFontConfigure.arrangedSubviews[0];
        firstView.hidden = YES;

visibility:

UIView * firstView = self.svViewFontConfigure.arrangedSubviews[0];
        firstView.hidden = NO;

as using stack view, all constraints will be keeped!

Document

Hobnob answered 25/9, 2016 at 12:47 Comment(4)
Seems like a really good solution actually, but it's worth to note that it needs iOS9+.Petronilapetronilla
I used your brilliant solution (+1 for you, thanks so much!!) but I connected via IBOutlet directly the view I wanted to show and hide, so I have to type just one line of code! :)Strepphon
This answer actually not correct. Android View.GONE removes view on UI. For example if you set View.GONE a element, views below that wiew will shift up. So your suggestion just hides the view which is equal to View.HIDE. Look at this answer : #11557107Coughlin
I did not search on android api... But I'm mobile developer, so I know mechanic... In Android with boolean flag view can be viewable or not(Gone,Visible) If it removes from ui it will be hard to add again... but in ios,it in layout but with no spaces.... Moreover There is officialy ios hidden property which take place...UIStackview hidden property like android View.GoneHobnob
K
16

add a height constraint to your view as follows:enter image description here

then make an outlet for the height constraint in your viewController file as follows:enter image description here

& then in your viewDidLoad method change constraint height to 0 as follows:

override func viewDidLoad() {
    super.viewDidLoad()
nsLcButtonHeight.constant = 0
}
Kex answered 20/1, 2016 at 16:54 Comment(1)
constant height sucks, I use equal height and multiplier, for example to take 25% of parent view, any example for it?Vascular
C
8

To achieve Androids.GONE functionality on iOS is to use a UIStackView. After that hide the child by position. (Apples documentation)

SWIFT 4:

let firstView = cell.rootStackView.arrangedSubviews[0]
    firstView.isHidden = true // first view gone

It's a table cell example, just put both insides Stack view and get item for GONE the child.

enter image description here

Chlamydospore answered 18/2, 2018 at 6:43 Comment(0)
N
6

What you can do is to group your views under a stack view. Then when you hide a particular view, the remaining views will be shifted automatically to fill the space.

You may want to check out the Apple Documentation on Stack Views: https://developer.apple.com/reference/uikit/uistackview

or online tutorials such as: https://www.appcoda.com/stack-views-intro/

Numbersnumbfish answered 5/2, 2017 at 5:3 Comment(0)
R
1

1) If your buttons are placed vertically then you must set the height to 0 and in case of horizontally placed buttons, try setting width to 0 or you can set both to 0.

OR

2) you could try this approach which sets button2 on top of button1:

- (void)viewDidLoad
{
[super viewDidLoad];

UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button1 setTitle:@"hello" forState:UIControlStateNormal];

UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button2 setTitle:@"world" forState:UIControlStateNormal];

[button1 sizeToFit]; [button2 sizeToFit];
[button2 setFrame:CGRectMake(button1.frame.origin.x, button1.frame.origin.y, button2.frame.size.width, button2.frame.size.height)];

[self.view addSubview:button1];
[self.view addSubview:button2];

}
Rinarinaldi answered 26/7, 2013 at 9:14 Comment(0)
P
1

https://github.com/tazihosniomar/LayoutManager

i hope it will help you .

Portecochere answered 13/5, 2014 at 15:33 Comment(0)
C
1

This question is pretty old but the closet thing I've found is setting additional constraints (so the views around the "gone" view know what to do once it's missing)

A  which you want to be     A
|  after setting B to gone  |
B                           C
|                               
C                               
  1. Set a lower priority (750) constraint from C to A.
  2. Add B's top and bottom constraints (or left and right if you want your view to collapse horizontally) to an NSLayoutConstraint array bConstraints. Do this by:
    1. Control click and drag from the constraint to the ViewController
    2. Change Connection from Outlet to Outlet Collection
    3. For name put bConstraints.
    4. Hit connect. This will create an @IBOutlet var bConstraints: [NSLayoutConstraint]! in your ViewController
    5. To add additional constraints: drag from the constraint in Storyboard to the @IBOutlet variable name
  3. Then hide B

    B.hidden = true
    NSLayoutConstraint.deactivateConstraints(bConstraints)
    
  4. To unhide

    B.hidden = false
    NSLayoutConstraint.activateConstraints(bConstraints)
    

Obviously the more and more views you have the more complex this grows, as you need additional constraints from each view

Corticate answered 6/1, 2017 at 21:59 Comment(7)
it would be more helpful if you explained why you couldn't implementCorticate
The second point. I am working in Xamarin though. Still haven't found a solution for this problem. Don't know how you should construct a NSLayoutConstraint array with B constraints. I assume it is done programatically, would be nice to see the code for that. Your method seems to me to be the most reasonable way of tackling this problem, however not easy to implement with just pseudo-codeShoot
I haven't used Xamarin. The way it's done in XCode is: ctrl-click and drag from the constraint to the ViewController (this is similar to how you wold create an IBOutlet in xcode). In the popup that appears (looks similar to i.sstatic.net/JegLK.png) change the "Connection" drop down menu from Outlet to Outlet Collection. For additional constraints, ctrl drag directly to the variable name. I can upload sceenshots later today (in ~8 hours)Corticate
so the NSLayoutConstraint array is the outlet collection, got a bit lost here haha, tks for taking your time to answer my questions :)Shoot
yes, i'll update the answer to be more clear. So the solution is working for you?Corticate
I am still trying, but finding hard to make the outlet connection in xamarin. The other problem is that I have an UIImageView with center.y connected to the right side of the B view which is the view that I need to hideShoot
You shouldn't need to involve subview constraints at all. Are you having difficulty selecting the constraint so you can ctrl-drag it? You can ctrl-drag from the document outline if it's easier than having to select the constraint in the interface builder - static1.squarespace.com/static/56ddcaef01dbae76cf85000d/t/…Corticate
L
0

As my research has shown, not even AutoLayout can help you. You have to manually replace the views affected by the optionally shown component (in my case, all the views to the bottom of the optional view, but you I am sure you can adapt this to handle all the buttons to the right of your optional button):

- (IBAction)toggleOptionalView:(id)sender {
    if (!_expanded) {
        self.optionalView.frame = CGRectMake(self.optionalView.frame.origin.x, self.optionalView.frame.origin.y, self.optionalView.frame.size.width, _optionalHeight);
        self.bottomView.frame = CGRectMake(self.bottomView.frame.origin.x, self.bottomView.frame.origin.y+_optionalHeight, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
        _expanded = YES;
    } else {
        self.optionalView.frame = CGRectMake(self.optionalView.frame.origin.x, self.optionalView.frame.origin.y, self.optionalView.frame.size.width, 0);
        self.bottomView.frame = CGRectMake(self.bottomView.frame.origin.x, self.bottomView.frame.origin.y-_optionalHeight, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
        _expanded = NO;

    }
}

It is advisable not to hard-code the height/width of the optional components, otherwise your code breaks every time you edit the XIB/Storyboard. I have a field float _optionalHeight which I set in viewDidLoad, so it is always up to date.

Leddy answered 14/3, 2014 at 10:5 Comment(0)
W
0

You can also clear the page, or at least certain cells of the page, and redefine the whole thing. It's fast and works well. I didn't write the code but found it in this pre-existing project I'm working on. Create ManagementTableSection and ManagementTableCell classes to manage it all. Sorry I can't provide better defined code.

Ween answered 17/9, 2014 at 14:38 Comment(0)
I
0

Building off the answer provided by Deniz, here is a solution using constraints in Swift

For example: If you have 3 views, A_view B_view and C_view vertically aligned in that order and you want to "Hide" B and also adjust the difference, add a constraint

B_view.removeFromSuperView()
var constr = NSLayoutConstraint(item: C_view, 
                                attribute: NSLayoutAttribute.Top, 
                                relatedBy: NSLayoutRelation.Equal, 
                                toItem: A_view, 
                                attribute: NSLayoutAttribute.Bottom,
                                multiplier: 1,
                                constant: 20)
view.addConstraint(constr)

constant is (in this case) the amount of vertical space between C_view and A_view

Indented answered 25/2, 2015 at 4:30 Comment(0)
A
0

I added a new property to a custom UIView implementation called "visible" which, when set to false, adds a constraint to collapse the view (I only added a width constraint since my list is horizontal, but the best way might be to add a height constraint of 0 as well).

var visible:Bool = true{
        didSet{
            if(visible){
                clipsToBounds = false;
                removeConstraint(hideConstraint!)
            }else{
                clipsToBounds = true
                addConstraint(hideConstraint!)
            }
        }
    }

You need to initialize the zero-width constraint on the view and add it as a field:

private var hideConstraint:NSLayoutConstraint?


func someInitFunction(){
    hideConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 0.0)
    ...
}
Aluino answered 25/2, 2015 at 13:32 Comment(0)
Y
-3

setHidden:TRUE/FALSE is the nearest equivalent to Android View.GONE/VISIBLE.

The View not necessarily take space if not visible!

I have made a ComboBox-Alike with a ListView laying on top of other views. I's only visible while selecting:

enter image description here

Yiyid answered 11/10, 2014 at 10:32 Comment(1)
you forgot that in android we also have view.invisible... view.gone is not similar to setHidden... its view.invisible that is similar to setHiddenShiism

© 2022 - 2024 — McMap. All rights reserved.