ios 在滚动视图中使用动态大小的控制器调整容器视图的大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35014362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sizing a Container View with a controller of dynamic size inside a scrollview
提问by TemptingFriendlyGrison
I'm trying to create a container view, with a controller that has a dynamic height, inside a UIScrollView and have it sized automatically using auto layout.
我正在尝试创建一个容器视图,它带有一个具有动态高度的控制器,位于 UIScrollView 内,并使用自动布局自动调整大小。
View Controller A is the scrollview, which has the container view included, along with more content below.
视图控制器 A 是滚动视图,其中包含容器视图,以及下面的更多内容。
View Controller B is the view controller that I want to have a dynamic size and for all the content to be displayed in full height in View Controller A's Scroll View.
视图控制器 B 是视图控制器,我希望它具有动态大小,并且所有内容都可以在视图控制器 A 的滚动视图中全高显示。
I'm having some problems getting the dynamic size of B to automatically set the size of the Container View in A. However if I set a height constraint on the Container View in A ,
我在获取 B 的动态大小以自动设置 A 中容器视图的大小时遇到一些问题。但是,如果我在 A 中的容器视图上设置高度约束,
It would be the expected output if View Controller B would also have 250 height. It also works fine for height 1000, so as far as I know, all the auto layout constraints are properly setup. Unfortunately, since the height should actually be dynamic, I would like to avoid setting a height constraint at all.
如果视图控制器 B 也有 250 高度,这将是预期的输出。它也适用于高度 1000,所以据我所知,所有自动布局约束都已正确设置。不幸的是,由于高度实际上应该是动态的,我想完全避免设置高度约束。
I'm not sure if there are any settings for view controller B I can set for it to automatically update its size depending on its contents, or if there are any other tricks I've missed. Any help would be much appreciated!
我不确定视图控制器 BI 是否可以设置任何设置以根据其内容自动更新其大小,或者是否有我错过的任何其他技巧。任何帮助将非常感激!
Is there any way to size the Container View in A according to how big the size of View Controller B is without setting a height constraint?
有没有办法根据视图控制器 B 的大小在不设置高度约束的情况下调整 A 中的容器视图的大小?
回答by Mischa
Yup, there is. I managed to achieve that kind of behavior in one of my own projects.
是的,有。我设法在我自己的一个项目中实现了这种行为。
All you gotta do is to tell the system that it should not add constraints that mimic the fixed frame set for your root view in Interface Builder. The best place to do this is in your container view controller when your embed segue is triggered:
你所要做的就是告诉系统它不应该添加模仿界面生成器中根视图的固定框架集的约束。执行此操作的最佳位置是在触发 embed segue 时在容器视图控制器中:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// You might want to check if this is your embed segue here
// in case there are other segues triggered from this view controller.
segue.destinationViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
}
Important:
重要的:
You gotta make sure that the view that you load into the container is constrained from top to bottom and you need to set the priority of one of the vertical constraints to a value lower than 1000. (It's a good practice to always use the bottom constraint for this.) This is necessary because otherwise Interface Builder will complain — with a good reason:
您必须确保加载到容器中的视图从上到下受到约束,并且需要将其中一个垂直约束的优先级设置为低于 1000 的值。(始终使用底部约束是一个好习惯为此。)这是必要的,否则 Interface Builder 会抱怨 - 有一个很好的理由:
At design time your root view has a fixed size (height). Now if all your subviews have a fixed height and are connected with fixed constraints that all have the same priority it's impossible to fulfil all these requirements unless the height of your fixed root view coincidentally matches exactly the total height of your subviews and the vertical constraints. If you lower the priority of one of the constraints to 999 Interface Builder knows which constraint to break. At runtime however — when the translatesAutoresizingMaskIntoConstraints
property is set as stated above — there is no fixed frame for your root view anymore and the system will use your 999 priority constraint instead.
在设计时,您的根视图具有固定大小(高度)。现在,如果您的所有子视图都具有固定高度并与所有具有相同优先级的固定约束连接,则不可能满足所有这些要求,除非您的固定根视图的高度恰好与子视图的总高度和垂直约束完全匹配。如果将其中一个约束的优先级降低到 999,Interface Builder 就知道要打破哪个约束。然而,在运行时——当translatesAutoresizingMaskIntoConstraints
属性设置如上所述时——你的根视图不再有固定的框架,系统将使用你的 999 优先级约束。
回答by acecilia
From the answer of @Mischa I was able to make the height of a containerView dynamic depending on its content doing this:
根据@Mischa 的回答,我能够根据其内容使 containerView 的高度动态化:
In the viewController of the containerView write:
在 containerView 的 viewController 中写:
override func loadView() {
super.loadView()
view.translatesAutoresizingMaskIntoConstraints = false
}
And taking care that the vertical constraints in IB are all set. Doing this you do not need to set view.translatesAutoresizingMaskIntoConstraints = false from outside the view controller.
并注意 IB 中的垂直约束都已设置。这样做你不需要从视图控制器外部设置 view.translatesAutoresizingMaskIntoConstraints = false 。
In my case I was trying to resize the container to a tableView inside the viewController. Because the tableView has a flexible height depending on its superview (so all OK for IB), I completed the vertical constraints in code by doing this:
在我的情况下,我试图将容器的大小调整为 viewController 中的 tableView。因为 tableView 有一个灵活的高度取决于它的超级视图(所以对 IB 来说一切都可以),我通过这样做完成了代码中的垂直约束:
@IBOutlet private var tableView: UITableView! {
didSet {
tableView.addConstraint(tableViewHeight)
}
}
private lazy var tableViewHeight: NSLayoutConstraint = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0)
And then observe the contentSize height of the tableview and adjust the constant of the tableViewHeight constraint programmatically when needed.
然后观察tableview的contentSize高度,并在需要的时候以编程方式调整tableViewHeight约束的常量。
回答by Teodor Ciuraru
Swift 4, Xcode 9
斯威夫特 4,Xcode 9
The accepted answer alone didn't solve the problem for me.
单独接受的答案并不能解决我的问题。
My hierarchy: ScrollView --> Content View (UIView) --> Views | Container View | Other Views.
我的层次结构:ScrollView --> Content View (UIView) --> Views | 集装箱视图 | 其他观点。
I had to add the following constraints to make both the ScrollView and Container dynamically adjust:
我必须添加以下约束才能使 ScrollView 和 Container 动态调整:
- ScrollView: Top, Bottom, Leading, Trailing to Superview (Safe Areas)
- Content View: Top, Bottom, Leading, Trailing, Equal Width to ScrollView, but also with Equal Heights (constraint with a lower priority: 250).
- Views: normal auto-layout constraints.
- Container View: Top, Bottom to neighbor views, Leading and Trailing to Safe Area.
- Container View's embedded VC: Everything constraint connected vertically with the bottom constraint set to a lower priority, but bigger than the Content View's Equal Height one!In this case, a priority of 500did the trick.
- Set
view.translatesAutoresizingMaskIntoConstraints = false
in eitherprepareForSegue()
or inloadView()
as other answers stated.
- ScrollView:顶部、底部、前导、尾随到超级视图(安全区域)
- 内容视图:顶部、底部、前导、尾随、与 ScrollView 等宽,但也具有等高(较低优先级的约束:250)。
- 视图:正常的自动布局约束。
- 容器视图:顶部、底部到相邻视图、前导和尾随到安全区域。
- 容器视图的嵌入式 VC:所有约束垂直连接,底部约束设置为较低的优先级,但比内容视图的等高优先级大!在这种情况下,优先级为500就成功了。
- 设置
view.translatesAutoresizingMaskIntoConstraints = false
在任一prepareForSegue()
或loadView()
作为其他的答案说。
Now I have a dynamically adjustable Container View inside an auto-resizing Scroll View.
现在我在自动调整大小的滚动视图中有一个动态可调的容器视图。
回答by Stuart Pattison
Building on @Mischa's great solution to this problem, if the container embeds a dynamically sized UITableView, then you need to look at overriding it's contentSize and intrinsicContentSize, as well as setting translatesAutoresizingMaskIntoConstraints = false
as per the accepted answer.
基于@Mischa 对此问题的出色解决方案,如果容器嵌入了动态大小的 UITableView,那么您需要查看覆盖它的 contentSize 和internalContentSize,以及根据translatesAutoresizingMaskIntoConstraints = false
接受的答案进行设置。
When the parent view loads and sets up the container view, the intrinsic height of each of the UITableViewCells is inferred to be 0, therefore the UITableViewDelegate method of:
当父视图加载并设置容器视图时,每个 UITableViewCells 的固有高度被推断为 0,因此 UITableViewDelegate 方法:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
will not be called. This makes the UITableView appear as though it has no content.
不会被调用。这使得 UITableView 看起来好像没有内容。
Overriding the intrinsic content size to return the actual content size means that the tableview is displayed with the size it's contents require.
覆盖内在内容大小以返回实际内容大小意味着 tableview 以其内容所需的大小显示。
A great articleby Emilio Peláez goes into more depth on this topic.