Horizontal squares with equal spacing between

Viewed 165

I'm trying to make a row of 5 equal squares (each 50x50) with spacing 20dp between them. I don't want anything to stretch, but at the same time I want to make it so that if I hide one of the squares, the others move over.

For example:

+-----+    +-----+    +-----+    +-----+    +-----+
| 50  | 20 | 50  | 20 | 50  | 20 | 50  | 20 | 50  |
| x50 |    | x50 |    | x50 |    | x50 |    | x50 |
+-----+    +-----+    +-----+    +-----+    +-----+

Then, if I set the middle square to isHidden = true, I'd want the others to move over:

+-----+    +-----+    +-----+    +-----+
| 50  | 20 | 50  | 20 | 50  | 20 | 50  |
| x50 |    | x50 |    | x50 |    | x50 |
+-----+    +-----+    +-----+    +-----+

Is this possible? My first thought was a stack view, but I don't think that would work since they're meant to adjust spacing.

3 Answers

Use UIStackView...

  • No Width or Trailing constraint.
  • Distribution: Fill
  • Spacing: 20
  • give each subview Width and Height constraints of Equal to Constant: 50

You end up with:

   1          2          3          4          5
+-----+    +-----+    +-----+    +-----+    +-----+
| 50  | 20 | 50  | 20 | 50  | 20 | 50  | 20 | 50  |
| x50 |    | x50 |    | x50 |    | x50 |    | x50 |
+-----+    +-----+    +-----+    +-----+    +-----+

Remove view #3 with:

let v = stackView.arrangedSubviews[2]
v.removeFromSuperview()

You now have:

   1          2          4          5
+-----+    +-----+    +-----+    +-----+
| 50  | 20 | 50  | 20 | 50  | 20 | 50  |
| x50 |    | x50 |    | x50 |    | x50 |
+-----+    +-----+    +-----+    +-----+

You'll get the same result with:

let v = stackView.arrangedSubviews[2]
v.isHidden = true

The stack view will hide view #3, removing the space it is occupying. If you set .isHidden back to false, the view will re-appear in its original position, shifting views 4 and 5 back to their original spots.

You should use StackView. But to hide some square you need to set its alpha to 0, instead of make it hidden. In this case layout will stay the same - you can hide some squares, and other will stay on their positions. If you need other squares to fill empty space with given spacing between elements - use isHidden property.

  • For example there are 5 circles: 0-0-0-0-0.

  • Lets set 3 circle isHidden: 0-0-0-0.

  • And now set alpha of 3 circle to zero: 0-0- -0-0.

There are many ways to do it, and StackView mentioned in the other answer is a great choice if you can use it. If not, yo can also:

  1. Have a a width constraint on your 50px item (which you probably do already) for each item. When you want to hide an item, also set its width constraint to 0.0. When you are showing the item, set it back to 50.0.

    yourWidthConstraint.constant = visible ? 50.0 : 0.0
    
  2. Always hide the last item, and simply shift the content of other items. For example if each item is a UIImageView:

    for i in hiddenIndex...lastVisibleIndex-1 {
        element[i].image = element[i + 1].image
    }
    element[lastVisibleIndex].isHidden = true
    
Related