2

Can I setup constrains on storyboard view controller views so that I will have three views one next to other when there is enough horizontal space. In other case it will "float" one of views to next line?

Like on this example:

  1. Enough space enough space

  2. Texts causing third view to "float" enter image description here

Maybe stack views can help here?

Fishman
  • 1,737
  • 1
  • 25
  • 42
  • Override this method systemLayoutSizeFittingSize and follow this :- http://www.programmingcrew.in/2016/06/collection-view-inside-table-view-with.html – pkc456 Jun 07 '16 at 06:54

2 Answers2

3

There is no reason to expect the auto layout system to be able to accomplish this, nor can it.

What you want to use here is a collection view (UICollectionView) and have each of your views be a cell in the collection view. In fact, if you look at your views, they look quite the reusable views, where each one has an icon, a title and a detail text. A collection view can be set up to put cells one next to the other until there is no more space, after which cells are added below, and so on.

You can then setup your scene to layout around your collection view using auto layout, where other views would reposition correctly below the collection view content when the collection view grows in height.

See this layout as an example of what you need.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • Well. That's how I have done it. Using combination of content hugging/compresion constraints for reusable cells. However it is not always as I would like it to be. Collection view is centering my cells when only one fits into row. – Fishman Jun 05 '16 at 19:58
  • Collection views are very robust. Most likely you haven't implemented the layout properly. I have updated my answer with an example layout that should implement what you need. – Léo Natan Jun 05 '16 at 20:00
  • I see how it can be done. However can I do the same with just constraints? Without manual calculation of layout attributes? – Fishman Jun 05 '16 at 20:04
  • It's possible. Since iOS 8, collection view cells can calculate their own attributes when the cells are defines using auto layout. So setup your cells, then let the system figure out the attributes. See here: https://www.shinobicontrols.com/blog/ios8-day-by-day-day-37-autosizing-collection-view-cells – Léo Natan Jun 05 '16 at 20:06
  • I get to solution almost/(or maybe) identical to one described in blog you've linked. And everything is almost ok. However I would like to avoid centering if there is only space for single cell. Like it is in case of "clicks-and-mortar" from shinobi blog example. – Fishman Jun 06 '16 at 07:08
  • Did you look at `UIXPackedLayout`? It solves your need. You can use that together with your cells, – Léo Natan Jun 06 '16 at 18:40
2

No. There is no way to setup views and constraints in a storyboard that automatically float into a new row if they don't fit into the same row.

(In my opinion that's a big weakness of the Autolayout system.)

The reason for that lies in the concept of constraints: Mathematically they represent linear equations that are normally independent for the x and y dimension. The only exception are aspect ratio constraints that connect the width of a view with the height of that (or another) view. But I cannot think of a way how you could use an aspect ratio constraint to break views into a new line if needed.

When the system resolves your constraints at run-time and computes the actual frames of your views it simply solves the system of linear equations for each dimension (or for both dimensions if an aspect ratio constraint is present). Adding the option of floating views to the Autolayout system would make the whole layout process a hell of a lot more complicated because you cannot describe that behavior as a simple linear equation.

(Stack views won't help as they only work for one dimension as well: either x or y.)

Recently, I needed the very same floating behavior you described and created a FloatingContainerView subclass of UIView. I generalized it so you can use it for any kind of view and translated it into Swift.

You can now find it on GitHub:

https://github.com/mischa-hildebrand/FloatingContainerView

Mischa
  • 15,816
  • 8
  • 59
  • 117
  • Seems reasonable. I'd love to see what you have done so far. Just to highlight... how have you approached "floating" aspect of your view? – Fishman Jun 05 '16 at 19:49
  • Why reinvent the wheel, when you already have a generalized view for this purpose exactly (and many others) - `UICollectionView`? – Léo Natan Jun 05 '16 at 19:56
  • The idea is to create a container view inside which you place all your views that should be floating and give it a custom class `FloatingContainerView`. Set its `translatesAutoresizingMaskIntoConstraint = NO` so you can use Autolayout and connect it with constraints in your storyboard. Inside your custom class you keep a reference to all your floating views in an array. In the `layoutSubviews` method you iterate over all those views, set `translatesAutoresizingMaskIntoConstraint = YES` for each and position them manually. You'll need to override `intrinsicContentSize` as well. – Mischa Jun 05 '16 at 19:58
  • @Mischa Yes, this is called a collection view. – Léo Natan Jun 05 '16 at 20:01
  • @LeoNatan: There are cases in which a `UICollectionView` is overkill in my opinion. But you are correct, I'd implement this with a collection view as well as it's all the very same cell type for all cells. – Mischa Jun 05 '16 at 20:02
  • Even if not, since each cell is now (since iOS 8) able to provide its own layout attributes, it is very easy to define many custom cell types, and let the collection view layout figure it out. – Léo Natan Jun 05 '16 at 20:04
  • I guess that's a question of personal taste in the end. On the one hand a collection view comes with an overhead like a scroll view etc. On the other hand you need to implement your custom cell(s), the data source and the delegate methods. That's a lot of work if you just want to add, say, four or five check boxes in a row that can break into the next one if needed. – Mischa Jun 05 '16 at 20:08
  • 1
    Yes, but would take longer to implement an alternative. What you could do is some custom view that contains a collection view as a subview, and implements all that is needed. Then to the outside world, it would work like a normal view. That would be best of both worlds, and indeed how many of the system views are implemented. (Date picker, alert controllers, etc. ) – Léo Natan Jun 05 '16 at 21:03
  • Sounds like a solid approach. However, once you have coded the alternative (without the collection view) it'll be a quick solution as well that works just as you described without the overhead. – Mischa Jun 05 '16 at 21:39
  • 2
    @Fishman: I put my `FloatingContainerView` class on GitHub as promised. :) See the link above. Just in case the collection view thing doesn't work for you. (However, as stated in my comment above I'd strongly suggest using a collection view in your case. Leo is right.) – Mischa Jun 06 '16 at 00:23