使用 AutoLayout 在不同高度的两列内堆叠 [英] Using AutoLayout to stack within two Columns of varying Heights

查看:18
本文介绍了使用 AutoLayout 在不同高度的两列内堆叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

针对 iOS 8.1

我正在使用 AutoLayout 在 TableCell 中布置多个标签.其中一些标签是可选的,有些可以包装它们的文本.它们分为两个列",这些列只是 TableCell 的 ContentView 中的两个 UIView.我的约束以编程方式应用.

第二次更新

没有

这里有几张屏幕截图,展示了设置压缩和拥抱优先级时的样子.背景色用于调试

普遍的问题是包含视图(紫色和红色)将自己的大小调整为两者中较小的一个.正如您在顶部看到的那样,优先级 3"正在被削减,因为左列容器不需要更高.

在下一个示例中,没有 Priority 标签,但 EventDate 被压缩.

解决方案

以下答案已经编写和测试.它在 iPhone & 上正常工作iPad,肖像和景观.最高的柱子获胜,另一个柱子只占用它需要的空间.如果需要,它甚至可以修改为垂直居中对象.它解决了垂直剪切标签问题,以及动态缩放.

初步建议

  • 如果可以,请使用Storyboard.您可以使用最先进的 GUI 直观地测试所有约束.
  • 不要修改拥抱、压缩甚至UILabel高度:让每个标签垂直占用它需要的空间,并且只添加顶部和侧面锚点
  • 使用额外的视图作为容器来定义每列的宽度.使用 multiplier 得到,比如说 2 分之三和 1 分之三.
  • 通过在最低标签的底部添加单个高度约束(leftColumn.bottom Equal minimumLeftLabel.bottom),让这些视图计算它们的理想高度
  • 不要动态添加或删除视图;而是隐藏它们,以便它们保留相关的约束.

解决方案说明

为简单起见,我创建了 2 个子视图,每列 1 个,并将它们并排放置.它们锚定在顶部/左侧和顶部/右侧,它们的宽度是计算出来的,它们的高度来自它们各自的内容(*).

左右子视图有一个 1/2 multiplier,我添加了一个 2 像素的 constant 作为边距.这两列内的标签左右锚定(leading space 到容器,trailing space 到容器),有 8 像素的边距.这可确保标签不会溢出其列.

  1. 考虑到 UITableViewCell 的高度是 2 个内部列中最大的.换句话说,containerView.height >= left.height containerView.height >= right.height.
  2. 确保您没有删除任何不可见的标签.view.hidden 不会破坏你的约束,这就是你想要的.
  3. 将每个UILabel 锚定到容器的左侧和右侧,最上面的也锚定到容器,但每个后续的label.top 都应该锚定到上面一个的.bottom它.这样,您的内容就会流动.如果需要,您可以添加边距.

(*) 最后一个关键是将每一列的高度与列上的约束联系起来,使其等于该列最低标签的 .bottom.在上面的示例中,您可以清楚地看到蓝色背景的右列比左列短.

虽然我看到您需要代码解决方案,但我在不到 15 分钟的时间内使用 Storyboard 创建了我的示例.它不仅仅是一个概念,它是一个实际的实现.它只有 0 行代码,适用于所有 iOS 设备.顺便说一下,它也有 0 个错误.

所有约束的列表

注意这里和那里散布的 >=.它们是使您的列独立高的关键.

NSLayoutContraint 对于 LR 几乎相同.

此处获取故事板和详细文章那里.

Targetting iOS 8.1

I am using AutoLayout to lay out a number of Labels in a TableCell. Some of those Labels are optional and some can wrap their Text. They are split across two "Columns", these columns are simply two UIViews in the TableCell's ContentView. My constraints are applied programatically.

SECOND UPDATE

Without SwiftArchitect's answer below I would not have solved this and have accepted his answer. However because mine is all in code, in a custom tablecell, I have also added a separate answer below

UPDATE

In an attempt to stop the labels from stretching to a size larger than they needed to be I had previously set the SetContentHuggingPriority and SetContentCompressionResistancePriority to 1000 as I belived this was the equivalent of saying "I want the Label to hug its content to its exact height and I do not want it to ever be compressed vertically" This request was clearly not being complied with by AutoLayout as you can see in the Red and Pink examples below.

this.notesLabel.SetContentHuggingPriority(1000, UILayoutConstraintAxis.Vertical);
this.notesLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);

I removed the setting of these priorities and the labels are no longer being squashed which was my original issue. Of course now certain labels are stretched beyond the height they need to be.

  1. Why does removing the Hugging and Compression priorities fix my issue?
  2. How can I get the text in the red box (red box not part of the cell added later) to not expand without going back to my previous issue?

Here are a couple of screenshots of what it did look like when the Compression and Hugging priorities where set. The background colours are for debugging

The general problem was that the Containing View's (colored purple and red) were sizing themselves to the smaller of the two. As you can see in the top one "Priority 3" is being cut because the left column container doesn't need to be any higher.

In this next example there is no Priority label but the EventDate is being squashed.

解决方案

The following answer has been written and tested. It works properly on iPhone & iPad, portrait & landscape. The tallest column wins, and the other one just takes the space it needs. It can even be modified to vertically center objects if need be. It addresses the vertically clipped label concerns, as well as dynamic scaling.

Preliminary advice

  • Use a Storyboard if you can. You can test all your constraints visually with a state-of-the-art GUI.
  • Do not tinker with hugging, compression, or even UILabel height: let each label take the space it needs vertically, and only add top and side anchors
  • Use extra views as containers to define the width of each column. Use multiplier to get, say 2 thirds and 1 third.
  • Let these views calculate their ideal height by adding a single height constraint to the bottom of the lowest label (leftColumn.bottom Equal lowestLeftLabel.bottom)
  • Do not add or remove views dynamically ; rather, hide them so that they preserve the associated constraints.

Solution Description

For simplicity, I have created 2 subviews, 1 for each column, and positioned them side by side. They are anchored on top/left and top/right, their width is calculated, and their height is derived from their respective content(*).

The left and right subviews have a 1/2 multiplier, to which I added a constant of 2 pixels for margin. The labels inside these two columns are anchored left and right (leading space to container and trailing space to container), with an 8 pixels margin. This ensure no label ever bleeds beyond its column.

  1. Consider that the height of your UITableViewCell is the largest of the 2 inner columns. In other words, containerView.height >= left.height and containerView.height >= right.height.
  2. Ensure you are not deleting any of the invisible labels. view.hidden will not disrupt your constraints, and that is what you want.
  3. Anchor each UILabel left and right to container, the uppermost to the container as well, but every subsequent label.top should be anchored to the .bottom of one above it. This way, your content will flow. You can add margins if you want.

(*) The final key is to tie the height of each column with a constraint on the column to equal the .bottom of the lowest label for that column. In the example above, you can clearly see that the right column, with a blue background, is shorter than the left one.

While I see you wanted a solution in code, I created my example using a Storyboard in less than 15 minutes. It is not merely a concept, it is an actual implementation. It has exactly 0 lines of code, and works on all iOS devices. Incidentally, it has also 0 bugs.

List of All Constraints

Notice the >= sprinkled here and there. They are the key to making your columns independently tall.

The NSLayoutContraint are virtually identical for L and R.

Get the Storyboard here, and a detailed article there.

这篇关于使用 AutoLayout 在不同高度的两列内堆叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆