问题
I have a UIViewController
on my storyboard that has 2 subviews side-to-side horizontally. I added constraints to fix the leading and trailing edges to a constant (20 pts), and another constraint to keep the widths equal. If I assume the following, it should be possible to calculate what the width of each subview will need to be:
- the subviews do not overlap
- there are no other views present (horizontally, at least)
- the width of the screen (the superview) is known
However, XCode gives me a warning that my views are horizontally ambiguous. I'm guessing that means that XCode is not making one of these assumptions, but which one is it? And is there a way for me to instruct XCode to make that assumption?
EDIT: Okay, played with it a bit and got the warning to go away, but it looks like it's not making the first assumption - it's just setting each subview's width to superview.width - 40
, and happily burying one view underneath the other. So the question is how to I stop them from overlapping?
EDIT 2: Okay, my actual screen is a lot more complicated than my simple example. Here's what I got:
So in this setup I have 4 views that are vertically and horizontally staggered. I want the blue, red, and purple views to all be the same subview.frame.size.width = superview.width - 60
. The blue and purple are lined up in the left column, and the red is alone in the right column, and all the gaps (between the two columns and between each column and it's nearest edge) are at a constant (20 pts). These 3 tables have a variable height, which I will be setting programmatically as described in James's answer here. At the bottom is a pink view that stretches the width of the screen (minus gaps), and sits at a constant 20 pts below either the purple or the red view, whichever is lower (which I'm attempting to do by giving it a spacing constraint of >= 20 to each view, and I hope that it will pick exactly 20 for one of them). Since all of the heights are dynamic and may not necessarily fit on the screen at the same time, I made their superview a UIScrollView
instead of the normal UIView
.
When all is said and done, I'm still getting a warning that all 4 of my views are horizontally ambiguous, and that the pink bar is vertically ambiguous. I think it's having trouble realizing what is supposed to go next to what, which is why it thinks it's horizontally ambiguous. And I think it's not picking to place the pink bar exactly 20 pts below either the purple or red views, which is why it thinks it's vertically ambiguous. Can anyone confirm or deny any of these suspicions? Or suggest a way around it? When I run it in the end, I just get this (I made the background of the scroll view yellow, which you can't tell in the storyboard screenshot):
回答1:
Vertically Ambiguous
Okay, I think I've solved the vertical ambiguous part. I added two vertical constraints between the pink and purple views and two vertical constraints between the pink and red views. For each pair, the first constraint is that the spacing between them must be > 20 pts, and it has 1000 priority. The second constraint is that the spacing is = 20 pts, but it only has an 800 priority.
For example, if the bottom of the purple view ends up being lower than the bottom of the red view (as it is in my first screenshot), Xcode should try to set the vertical distance between the pink and red views = 20, but it will realize that that conflicts with condition that the space between the purple and pink being >= 20. Since the >= constraint has higher priority, the = constraint will be ignored. Now, when Xcode looks at the constraint that the spacing between the purple and pink views being = 20, it checks that against the constraint that the pink and red must be separated by at least 20. Since the bottom of the red view is higher than the bottom of the purple view, the >= 20 constraint between the red and the pink still passes.
So TL;DR, you can set up a view to have a spacing at a given value (x) from the most extreme of multiple views by giving it a >= x constraint with 1000 priority and giving it a = x constraint with <1000 priority for each view you are considering - and my vertical ambiguity problem has been solved. I do not yet have a solution for the horizontal ambiguity for all 4 of the views.
Horizontally Ambiguous
Okay, I got the horizontally ambiguous part fixed now as well. What it boils down to is that constraints in scroll views (and therefore table views) work differently than they do for any other kind of view. Here's what the step-by-step looks like.
- Place the
UIScrollView
- Place a
UIView
into theUIScrollView
to serve as a "contentView
" for that scroll view - Add constraints to pin the
contentView
to all 4 corners of the scroll view AND pin it'swidth
andheight
(so 6 constraints between thecontentView
and it's superview - 2 more than usual). Note that thewidth
and theheight
can be pinned to something much larger than the normal screen size, which is probably why you are using a scroll view to begin with. - Add all of your other views you want in the
UIScrollView
(UIButtons
,UILabels
, etc. - I'm just going to assumeUILabel
from here on so I don't have to type as much, but any kind ofUIView
subclass will work) as subviews of thecontentView
, NOT directly as subviews of theUIScrollView
With this setup, the UILabel
s that are given constraints to their superview will constrain to the contentView
, which has a defined size, so nothing is ambiguous.
Alternatively, if you want to fix the sizes of your UILabel
s (or dynamically calculate them, depending on the functionality of your app) and let the contentView
expand to hold them:
- Place the
UIScrollView
- Place a
UIView
into theUIScrollView
to serve as a "contentView
" for that scroll view - Add constraints to pin the
contentView
to all 4 corners of the scroll view AND pin it'swidth
andheight
- create an outlet for the
width
constraints on thecontentView
(let's say we name itcontentViewWidthConstraint
) - place the
UILabel
s - fix the sizes of the
UILabel
s - create an outlet for the
width
constraints on theUILabel
s
Then in the code for viewWillLayoutSubviews
- add up the widths of all of the
UILabel
s and any gaps you want between them (as aCGFloat
, which I'll calltotalWidth
) - set
contentViewWidthConstraint.constant = totalWidth
And you're good to go! Note that I assumed you were setting the width in most of this example, but it should be just as applicable to height.
回答2:
The problem is that many different widths of the two views will satisfy the constraints that you've set up. Here are two examples (I drew the shapes stacked vertically to make it easier to see the overlap example):
You can add a horizontal space constraint with a value of 0.
来源:https://stackoverflow.com/questions/19253937/views-are-horizontally-and-vertically-ambiguous-with-complex-layout