Start with a UIImageView
and UILabel
. Constraint the width (or height) to your desired value (this is what you will use to change the size of the image later). Add a "aspect ratio constraint" to the UIImageView
and constraint it appropriately (I've used a ratio/multiplier of 1:1
, you will need to calculate it based on your original image


Select both the UIImageView
and UILabel
and "wrap" in a UIStackView

Adjust the properties of the UIStackView
to your needs

I used the above to allow the text or image to grow larger without constraining the other element
Okay, the fun part. Copy and paste the UIStackView
, align the second UIStackView
below the first, so it generates a "column". Select both and wrap in another UIStackView

Update the properties of the new UIStackView
...

Again, I'm focusing on allowing each group to expand without constraining the other
And now I have a container that looks something like...

Okay, now copy this new UIStackView
and paste it, align to the trailing edge (it's not important, but it will make it easier to describe) - this will give you a 2x2 grid. Select the two top most UIStackView
s and, again, wrap in another UIStackView

Again, I modified the UIStackView
properties to Aligment
to Center
and Distribution
to Equal Centering
Okay, now for some fun. Select three of the UIImageView
s (personally, I use the top/left one as the master) and remove their constraints (you can use the "Selected View/Clear Constraints option)

Select one of the "clean" UIImageView
s and Control+Drag to the "master" UIImageView
and add width and height constraints, so they will be equal to the master's

hint- You can hold down Command to select multiple constraints
Repeat for the other two "clean" UIImageView
s
I would know constraint the top most UIStackView
to the center of the view, or you can constrain it in any other way you want, but this makes it the primary anchor.
Okay, but why?
Well, now you only need to update a single constraint to update all the images!
Try it. Select the "master" UIImageView
, find it's width
constraint (you might need to go to the properties sheet) and change it's constant to something else. All the UIImageView
s should update!

At this point, I'd be binding this constraint to the UIViewController
so you can modify it within code.
Why stack the stacks this way?
That's a good question, you choices might differ, but, I choose to construct it this way so that the columns will remain entered with each other if the text values are different widths.

Is there a simpler way?
Oh, how I wish! Okay, this isn't a "bad" solution, but it does take some thought and about how to lay it out and don't ask me what will happen if the text is split over multiple lines - because it's not pretty.
A "different" approach might be to use a UIView
or a container view and then trying to generate the constraints between the images (horizontal and vertical alignment) and the constraint the text between the images in some meaningful way, but that becomes really complex really fast...
Then how do you align them to the parent view? This is why I'd use either a UIView
or container view, but then it becomes more complicated as you need to stop the API defining it's own constraints and make sure that you have the correct constraints for the top, bottom, leading and trailing edges
What happens when the text is longer/shorter then the images?! So if you only have some basic text, then the above should work reasonable well and should reasonably maintainable.