iOS中类似于Android View.GONE的可见性模式是什么?

80
我正在为iOS开发一个应用程序,使用带有AutoLayout的Storyboard。其中一个视图控制器有一组4个按钮,在某些情况下,我想让第一个消失。
如果我使用setHidden:TRUE方法,UIButton将变得不可见,但在视图中仍然占据空间,结果是一个“空洞”,我无法通过使其余的UIButton浮动到主视图的顶部来填充它。
在Android中,我只需使用View.GONE而不是View.INVISIBLE,但在iOS中,我被困在了这种行为中,并且我不想相信唯一的解决方案是手动(是的,我指编程)将其余元素移动到顶部。
我认为我应该能够设置某种约束条件,使一切像Android中那样自动化,但我没有成功。
在关闭Autolayout之前,有人可以指导我正确的方向吗?
我正在使用IB,但我也熟悉编程方面的内容。
更新:
将组件高度设置为0也没有帮助。
我尝试过类似于以下内容:
UIButton *b;
CGRect frameRect = b.frame;
frameRect.size.height = 0;
b.frame = frameRect;

将按钮的高度设置为零怎么样? - cahn
我尝试了类似这样的代码:UIButton * b; CGRect frameRect = b.frame; frameRect.size.height = 0; b.frame = frameRect;但是没有成功 :( - elbuild
我知道这是一个非常老的问题,但关于您的更新,将框架设置为0不会有帮助,如果您正在使用自动布局。您必须将高度约束设置为0。 - wyu
13个回答

41

为了解决问题,我添加了一个约束(NSLayoutAttributeHeight),将视图的高度设置为0:

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captchaView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0]];

11
Swift版本:self.view.addConstraint(NSLayoutConstraint(item:self.captchaView,attribute:.Height,relatedBy:.Equal,toItem:nil,attribute:.NotAnAttribute,multiplier:1.0,constant:0)) - iStar
1
这本应该是答案。 - Rick Royd Aban
2
如果我不知道所需视图的实际高度(例如,容器视图稍后呈现),该怎么办? - A. Petrov
@iStar 我使用了相同的代码,但它不起作用... https://dev59.com/HqPia4cB1Zd3GeqP6vqP - Sanjay Mangaroliya
太棒了!解决了我的难题。 - Rajitha Perera
显示剩余5条评论

21

这个问题的所有答案都不够高效。 在iOS上实现类似于Android setVisibility:Gone方法的最佳方式是先选择组件,然后在编辑器中嵌入Stack View, 将新的Stack View与IBOutlet连接,然后:

隐藏:

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

可见性:

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

使用堆栈视图,所有约束都将保持不变!

文档


实际上,这似乎是一个非常好的解决方案,但值得注意的是它需要iOS9+。 - user3533716
我使用了你的绝妙解决方案(+1 给你,非常感谢!!),但是我直接通过 IBOutlet 连接了我想要显示和隐藏的视图,所以我只需要输入一行代码! :) - Cristina De Rito
1
这个答案实际上是不正确的。Android View.GONE会从UI中移除视图。例如,如果您将View.GONE设置为一个元素,则该视图下面的视图将向上移动。因此,您的建议只是隐藏了与View.HIDE相等的视图。请参考以下答案:https://dev59.com/8Ggu5IYBdhLWcg3wHzoX - emin deniz
我没有在Android API上搜索过...但我是移动开发人员,所以我知道机制...在Android中,使用布尔标志,视图可以是可见或不可见的(Gone,Visible)。如果从UI中删除它,再次添加将会很困难...但在iOS中,它在布局中但没有空间...此外,有Officialy iOS隐藏属性占据位置...UIStackview隐藏属性就像Android View.Gone。 - Ucdemir

16

按照以下方式为您的视图添加高度约束:在此输入图片描述

然后在viewController文件中创建高度约束的输出口,如下所示:在此输入图片描述

& 然后在viewDidLoad方法中将约束高度更改为0,如下所示:

override func viewDidLoad() {
    super.viewDidLoad()
nsLcButtonHeight.constant = 0
}

1
常量高度很糟糕,我使用等高和乘数,例如取父视图的25%,有任何示例吗? - user924

8
要在iOS上实现类似于Android的.GONE功能,可以使用UIStackView。之后,通过位置隐藏子元素。(苹果文档SWIFT 4:
let firstView = cell.rootStackView.arrangedSubviews[0]
    firstView.isHidden = true // first view gone

这是一个表格单元格示例,只需将其放在Stack view内,并获取子项GONE

enter image description here


6

1

1) 如果你的按钮是垂直放置的,那么你必须将 height 设置为 0,在水平放置的按钮中,尝试将 width 设置为 0 或者两个都设置为 0。

或者

2) 你可以尝试这种方法,将 button2 放在 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];

}

1

1
这个问题很老,但我找到的最接近的方法是设置额外的约束条件(这样“消失”的视图周围的视图就知道它缺失后该怎么做)。
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)
    
显然,你的观点越多,这个过程就变得越复杂,因为你需要从每个观点添加额外的限制。

如果您能解释为什么无法实现,那将更有帮助。 - wyu
第二点。虽然我正在使用Xamarin,但仍未找到解决此问题的方法。不知道如何构建带有B约束条件的NSLayoutConstraint数组。我猜这是通过编程完成的,看到代码会很好。您的方法似乎是解决此问题最合理的方式,但仅凭伪代码实现并不容易。 - Gustavo Baiocchi Costa
我没有使用过Xamarin。在XCode中的操作方式是:从约束条件(ctrl-click)拖动到ViewController(这类似于在xcode中创建IBOutlet的方式)。在弹出的窗口中(类似于https://i.stack.imgur.com/JegLK.png),将“Connection”下拉菜单从“Outlet”更改为“Outlet Collection”。对于其他约束条件,可以直接从变量名(ctrl drag)进行拖动。我可以在今天晚些时候上传截图(大约8小时后)。 - wyu
所以 NSLayoutConstraint 数组是输出集合,我有点迷失了哈哈,谢谢你抽出时间来回答我的问题 :) - Gustavo Baiocchi Costa
是的,我会更新答案以使其更清晰。那么解决方案对您有效吗? - wyu
显示剩余2条评论

0
根据我的研究,即使是AutoLayout也无法帮助你。你必须手动替换受可选组件影响的视图(在我的情况下,所有位于可选视图底部的视图,但我相信你可以适应处理所有位于可选按钮右侧的按钮)。
- (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;

    }
}

建议不要硬编码可选组件的高度/宽度,否则每次编辑XIB/Storyboard时都会破坏您的代码。我有一个字段float _optionalHeight,在viewDidLoad中设置,因此始终是最新的。


0

您还可以清除页面,或者至少清除页面上的某些单元格,并重新定义整个页面。这很快速且效果良好。我没有编写代码,但是在我正在处理的这个现有项目中找到了它。创建ManagementTableSectionManagementTableCell类来管理所有内容。抱歉我无法提供更好的定义代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接