(I’m posting this question as S.O. (“Answer your own question”) format to make this recipe easy to find, and to get any other helpful perspectives).
Question: What is a convenient way to set a specific content size UIViews?
Use case driving the question:
I’m working with an app with many UIStackView
instances that display custom icons next to each other.
The stack view items are often UILabel
other times, simply UIView
.
Apple Docs say UILabel
is a type that sets its own intrinsic content size. And in many case that works out okay. However, for certain UILabel
, instances, the intrinsic content size is not set optimally, which can be challenging for getting UIStackView
to layout precisely.
In other cases, I create a UIView
where it is not optimal to subclass each UIView
I create, but rather render a CALayer
into the view after the view’s creation. Thus the UIView
cannot set its intrinsic size properly. Thus, when I use that as an item in UIStackView
, it sees the content CGSize as (0, 0), regardless of frame setting, and so UIStackView
doesn’t handle it properly even with spacing and custom spacing options.
Since I know the size of the layer whose graphics I’m rendering in advance, it would be helpful to be able to construct the UIView
with a predetermined size, similarly to the way people generally construct UIView(frame: CGRectMake(x, y, w, h)
, but in a way UIStackView
recognizes (e.g. intrinsic content size).
2
Answers
Here's a class that allows creation of views with a specific early known intrinsic content size (similar to the default
frame:
constructor), but a sizeUIStackView
honors, into which, for example,CALayer
objects can be rendered after the view's creation:Usage example:
The OP and I briefly discussed this design and I pointed out some potential sources of ambiguity:
size
and aframe
and thatframe
could have a different size (which is potentially useful but more likely a source of errors in my opinion). I suggested it should take anorigin
and asize
..zero
.Having thought about it some more, here’s a few more things I think could be improved:
frame
) initialiser saves the initial size, there isn’t really much value in having the convenience initialiser take an origin. Similarly, anyone wanting to specify a zero size could useinit()
or specify a frame so the convenience initialiser could require asize
without any loss of features.invalidateIntrinsicContentSize()
.The OP is obviously happy with their version and invited me to create my own answer. Here’s a version which addresses my comments: