Reputation: 187
In a XIB
file I have a CustomView
related to a class with the same name.
The view content is quite simple.
There are a vertical stackview and inside the stackview there are two labels. The stackview is vertically aligned to the view that contains it:
The first label (title) contains a static text (always a few characters). The second label (subtitle) can have variable length text.
I add this CustomView
with other similar views as a subview of a Content View
, as it was a “row”.
for i in 0...aViews.count {
var v = CustomView(frame: CGRect(x: 0, y: _y, width: 320, height: 100))
v.labelText = "my long label text ..."
contentView.addSubview(v)
// ...
}
As you can imagine, the title label should have a fixed position (top and left), that is, there cannot be a row with the title starting at 10 points and another at 14.
I must admit I naively thought the position of the label would have been automatically managed by the same fact that I aligned vertically the stackview. I was wrong and I noticed no problem at all, until they told me the second label, the subtitle, could contain more than one line.
I added lines to the label directly in the storyboard
, and found out that:
the container of the stackview doesn’t change its height
based on the height
of its content;
the position of the “fixed” elements is maybe vertically centered but not fixed;
What I need is the following:
Is this possible? How should I design my view?
Upvotes: 2
Views: 1787
Reputation: 77423
OK - looking at your project, you're not far off... just a couple key items.
In your CustomView.xib, you had no constraint between Fixed Label
and Date Label
. The result is that the Date Label
grows up from the bottom of the view, with nothing to stop it.
Also in your CustomView.xib, you had the Fixed Label
constrained to the trailing edge... I assume you want it left-aligned with Date Label
When creating your CustomViews, you were setting a height constraint of 100 -- which defeats the purpose of allowing the content to determine the size.
In CustomView class, you had contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
commented out. That line should be there.
In your view controller, you added a height constraint to contentView
with a low priority. Best option is to make that a Placeholder constraint (double-click the constraint, and select the Placeholder checkbox). That way the constraint is removed at run-time, but is there during design (and Storyboard doesn't complain).
You were doing a few other un-necessary things - likely you were trying different stuff to get it to work.
The view setup (adding your views) is best done in viewDidLoad()
-- definitely not in viewDidLayoutSubviews()
I'm guessing that, in your CustomView, instead of an explicit width of 200 you probably want to constrain the Date Label
leading and trailing, allowing it to horizontally stretch based on the device width... but I left it at 200.
If you can follow that information, you should be able to fix the issue(s). But, I put the project up as a GitHub repo for you, so you can get it in a "working" state, and so you can see the changes.
Here's the link to the repo: https://github.com/DonMag/ATester2
Here is the result:
And scrolled up a bit:
Upvotes: 1
Reputation: 1367
I think you are mixing absolute positioning of outer views (i.e. manually setting frames) and using autolayout constraints for their inner components, and wrongly expect the dynamic autolayout part to somehow "reach all the way up" to the outer views. For autolayout to do that, you'll need to use autolayout all the way up, including the way CustomViews
are positioned in your contentView
.
If for whatever reason you do not want to use a TableView or CollectionView for this you could also, for example, try adding your CustomView
s as arranged subviews to a vertical stackview that has top/bottom/leading/trailing constraints to contentView
, then replace the "Align Center Y" constraint of your CustomView
with "Align Top" and "Align Bottom" constraints to actually allow your labels to "push" from the inside if they need more vertical space.
Edit here's a quick sketch to illustrate that setup:
Edit 2 here are a couple of screenshots to clarify further. With a basic layout like this:
the result will look like this at runtime:
Note that the UIStackViews use the "Equal Spacing" Distribution in this example. If you want to create and add your CustomView
s programmatically, use the StackView's func addArrangedSubview(_ view: UIView)
.
Good luck!
Upvotes: 1