Skip to content
This repository has been archived by the owner on Dec 2, 2021. It is now read-only.

Flow layout #12

Open
dsmid opened this issue Jan 8, 2016 · 4 comments
Open

Flow layout #12

dsmid opened this issue Jan 8, 2016 · 4 comments

Comments

@dsmid
Copy link

dsmid commented Jan 8, 2016

Is it somehow possible to define a flow layout, i.e. define that view2 should be right to view1 but could potentially wrap if needed and place itself on the next row/column ?

@IjzerenHein
Copy link
Owner

Hmm, that's an interesting question. I don't see how that would be currently possible though. AutoLayout is a system of relational mathematical constraints, so it would be necessary to express that behavior using these constraints (in the form of: view.right = view.left * multiplier + constant). In order to make something "flow", it would be necessary to create "conditional" constraints.

We would need something like this:

if view.right > superview.right
  view.top = prevView.bottom + 10
else
  view.top = prevView.top

Let's discuss and explore this idea here.

@dsmid
Copy link
Author

dsmid commented Jan 14, 2016

Yes, if-then-else approach would work but it would be necessary to be able to test computed positions/dimensions.

Or there could be a 'break point' operator like '/'.
This: H:|[view1(>=500)]/[view2(>=500)] would mean H:|[view1(>=500)][view2(>=500)] if it fits and this:
H:[view1(>=500)]
H:|[view2(>=500)]
V:[view1][view2]
if it doesn't.

@IjzerenHein
Copy link
Owner

I really like that idea of a "break-operator" /, nice one. It keeps the whole vfl syntax very readable. 👍

I've explored the idea a little bit and found that it requires an additional constraint. When view2 wraps to the next line, it's horizontal position cannot be determined unambiguously. One could assume that it's "left" position is aligned with the super-view, but this doesn't have to be the case. It's very well possible that there is a margin/spacer between the super-view and view1 and this needs to be accounted for. For this situation I think we could use a stack-view syntax, like this:
H:|-10-[flowStack:[view1(500)]/[view2(500)]]
This way, when wrapped, it will know that view2 is to be placed to the left edge of flowStack.

Idea exploration from here on...

So in order to build something like this, we would still need to extend the underlying constraint system to support conditionals. When translating this vfl H:|[view1(>=500)]/[view2(>=500)] into constraints, I can imagine getting the following constraints (generated using the Visual Format Editor):

H:|[view1] // relation to superview

  {
    "view1": null,
    "attr1": "left",
    "relation": "equ",
    "view2": "view1",
    "attr2": "left",
    "constant": 0
  }

H:[view1(>=500)] // width of view1

  {
    "view1": "view1",
    "attr1": "width",
    "relation": "geq",
    "attr2": "const",
    "constant": 500
  }

H:[view2(>=500)] // width of view2

  {
    "view1": "view2",
    "attr1": "width",
    "relation": "geq",
    "attr2": "const",
    "constant": 500
  }

H:[view1][view2] // view2 follows view 1 (conditional)

  {
    "view1": "view1",
    "attr1": "right",
    "relation": "equ",
    "view2": "view2",
    "attr2": "left",
    "constant": 0
    "condition": "view2.right < superview.right" ???
  }

V:[view1][view2] // view2 follows view 1 vertically (conditional)

    "view1": "view1",
    "attr1": "bottom",
    "relation": "equ",
    "view2": "view2",
    "attr2": "top",
    "constant": 0
    "condition": "!(view2.right < superview.right)" ???
  }

H:|[view2] // view2 starts at the beginning of the next line (aligned to superview??) (conditional)

    "view1": "view1",
    "attr1": "left",
    "relation": "equ",
    "view2": "null",
    "attr2": "left",
    "constant": 0
    "condition": "!(view2.right < superview.right)" ???
  }

Hmm, it seems that using view2.right as an input condition isn't really possible, as view2.right itself is also affected by the condition, this creates a circular reference.

I think we'd need to create a dummy view view2_nonwrap ? which is always placed in the non-wrapped position. We could then test whether view2_nonwrap is beyond the allowed right position and position "view2" accordingly.

H:[view1][view2_nonwrap(view2)] // dummy view for testing whether view2 needs to be wrapped

  {
    "view1": "view1",
    "attr1": "right",
    "relation": "equ",
    "view2": "view2_nonwrap",
    "attr2": "left",
    "constant": 0
  }

And then the condition would become view2_nonwrap.right < superview.right.
That looks a bit better already.

So hmm, but testing for < superview.right still doesn't feel quite right. What if you want to include a margin of 10px on the right-side. Hmm, I guess we could use the same stack-view approach I mentioned earlier for this...

And then we still need to figure out how to actually implement conditionals. Can it be done in autolayout alone or is it necessary to change the underlying cassowary/kiwi solver for this...
Thought-food for the next time...

Hope that makes any sense btw :)

cheers

@trusktr
Copy link

trusktr commented Dec 9, 2018

+1!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants