隐藏UIViews的AutoLayout?

Rya*_*huk 160 objective-c ios autolayout

我觉得这是一个相当常见的范例,显示/隐藏UIViews,通常UILabels,取决于业务逻辑.我的问题是,使用AutoLayout响应隐藏视图的最佳方式是什么,就像它们的帧是0x0一样.以下是1-3个功能的动态列表示例.

动态功能列表

现在我从按钮到最后一个标签有一个10px的顶部空间,当标签被隐藏时,显然不会向上滑动.到目前为止,我创建了这个约束的出口,并根据我显示的标签数量修改常量.这显然有点hacky,因为我使用负常量值将按钮向上推到隐藏的帧上.这也很糟糕,因为它不受实际布局元素的限制,只是基于其他元素的已知高度/填充的偷偷摸摸的静态计算,并且明显地与AutoLayout的构建作斗争.

我显然可以根据我的动态标签创建新的约束,但这是很多微观管理和尝试折叠一些空白的很多冗长.有更好的方法吗?更改帧大小0,0并让AutoLayout在没有约束操作的情况下完成它的工作?完全删除视图?

但老实说,只需从隐藏视图的上下文修改常量,只需要一行代码就可以进行简单的计算.重新创建新的约束 constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:似乎很重.

编辑2018年2月:用UIStackViews 来看Ben的回答

Max*_*eod 232

我个人对显示/隐藏视图的偏好是创建一个具有适当宽度或高度约束的IBOutlet.

然后我将constant值更新0为隐藏,或者应显示的值.

该技术的最大优点是将保持相对约束.例如,假设您有视图A和视图B,水平间隙为x.当视图A宽度constant设置0.f为时,视图B将向左移动以填充该空间.

无需添加或删除约束,这是一项重量级操作.简单地更新约束constant就可以了.

  • @MaxMacLeod只是为了确保:如果两个视图之间的间隙是x,为了使视图B从视图A位置开始,我们还必须将间隙约束常量更改为0,对吧? (9认同)
  • 还要感谢一个适用于包含其他视图的UIView的解决方案...... (6认同)
  • @MaxMacLeod感谢您的回答.我尝试使用包含其他视图的UIView来执行此操作,但是当我将其高度约束设置为0时,该视图的子视图不会被隐藏.此解决方案是否适用于包含子视图的视图?谢谢! (2认同)

Sim*_*lGy 96

0隐藏时使用常量和再次显示常量时使用常量的解决方案是有效的,但如果您的内容具有灵活的大小,则不满意.您需要测量灵活内容并设置一个不变的状态.这感觉不对,如果内容因服务器或UI事件而改变大小,则会出现问题.

我有一个更好的解决方案.

我们的想法是在隐藏元素时将0高度规则设置为具有高优先级,以便它不占用自动布局空间.

这是你如何做到这一点:

1.在接口构建器中以低优先级设置宽度(或高度)为0.

设置宽度0规则

Interface Builder不会对冲突大喊大叫,因为优先级很低.通过暂时将优先级设置为999来测试高度行为(禁止1000以编程方式进行变异,因此我们不会使用它).接口构建器现在可能会对冲突的约束大喊大叫.您可以通过将相关对象的优先级设置为900左右来解决这些问题.

2.添加插座,以便您可以在代码中修改宽度约束的优先级:

插座连接

3.隐藏元素时调整优先级:

cell.alertTimingView.hidden    = place.closingSoon != true
cell.alertTimingWidth.priority = place.closingSoon == true ? 250 : 999
Run Code Online (Sandbox Code Playgroud)


Ben*_*ard 81

UIStackView可能是iOS 9+的方法.它不仅处理隐藏的视图,如果设置正确,它还将删除额外的间距和边距.

  • 在UITableViewCell中使用UIStackView时要小心.对我来说,一旦视图变得非常复杂,滚动开始变得波涛汹涌,每当一个单元格滚入/滚出时它就会断断续续.在幕后,StackView正在添加/删除约束,这对于平滑滚动来说不一定足够有效. (7认同)
  • 很高兴给出一个关于堆栈视图如何处理这个问题的小例子. (7认同)
  • 五年后......我应该更新并将其设置为接受的答案吗?它现在可用于三个发布周期. (3认同)

Mit*_*iya 11

在这种情况下,我将Author标签的高度映射到适当的IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;
Run Code Online (Sandbox Code Playgroud)

当我将约束的高度设置为0.0f时,我们保留"填充",因为"播放"按钮的高度允许它.

cell.authorLabelHeight.constant = 0; //Hide 
cell.authorLabelHeight.constant = 44; //Show
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Sea*_*anR 6

这里有很多解决方案,但是我通常的方法又有所不同:)

设置两组约束,类似于Jorge Arimany和TMin的答案:

在此处输入图片说明

这三个标记的约束的常数值都相同。标记为A1和A2的约束将其优先级设置为500,而标记为B的约束将其优先级设置为250(或UILayoutProperty.defaultLow在代码中)。

将约束B连接到IBOutlet。然后,当您隐藏元素时,只需将约束优先级设置为高(750):

constraintB.priority = .defaultHigh

但是,当该元素可见时,将优先级设置回低(250):

constraintB.priority = .defaultLow

与仅更改isActive约束B 相比,此方法的优点(公认的次要优势)是,如果通过其他方法从视图中删除了过渡元素,您仍然会有工作约束。


Dan*_*iel 5

对视图进行子类化并覆盖func intrinsicContentSize() -> CGSize.CGSizeZero如果视图被隐藏,则返回.

  • 这很棒.但是,有些UI元素需要触发`invalidateIntrinsicContentSize`.你可以在重写的`setHidden`中做到这一点. (2认同)

Mat*_*ala 5

我刚刚发现要让 UILabel 不占用空间,您必须隐藏它并将其文本设置为空字符串。(iOS 9)

知道这个事实/错误可以帮助一些人简化他们的布局,甚至可能是原始问题的布局,所以我想我会发布它。