Flexbox could be implemented as a framework on top of this.
Flexbox could be implemented as a framework on top of this.
I too like constraint-based layout, but I have to admit flexbox is nice in that it has very predictable behavior. The main hangup I have with flexbox is that it doesn't allow for layout based on aspect ratios, but Yoga has extensions that resolve this issue.
I think that pg's point #2 from this post applies
http://paulgraham.com/popular.html
"It is a mistake to try to baby the user with long-winded expressions that are meant to resemble English. Cobol is notorious for this flaw. A hacker would consider being asked to write."
I've spend a few months playing with Cassowary before working on css-layout and had long chats with its creator Greg Badros and the people behind https://gridstylesheets.org/.
Cassowary underlying abstraction is a linear inequation solver. So you give it a bunch of constraints of the form ax + by + cz + d < 0 and it's going to give you values for x, y and z.
## There are two innovations in Cassowary:
1) There's a concept of strength (required, strong, medium, weak) which allows you to define which rules should be dropped in case of conflicts. This is a very different way to think about building UI and was a really fun exercise.
That said, I had to build a dedicated tool to show me which rules where overridden or why otherwise it was very hard to understand what happened when the layout didn't work as I expected.
2) Cassowary is an iterative solver, this means that it's not going to recompute the entire simplex from scratch on every tiny update.
## The biggest issue with Cassowary is that you cannot express everything with a linear system of equations:
The most annoying instance is line breaking. You cannot encode how lines are going to break as a set of linear inequations. In practice, what happens is that you're going to "fake it" by iterating outside of the simplex by first giving it a rough size and then do another pass with the real one. It usually works but you are not guaranteed for it to converge nor to have the optimal layout.
## In practice
It's extremely painful to write all the inequations yourself. If you want to have a container with an item of height 100px with 5px of padding it looks like.
obj.left = parent.left + 5
obj.top = parent.top + 5
obj.right = parent.right - 5
obj.height = 100
parent.height = obj + 5
For every single object you need to define 4 inequations to "define": top, left, width and height which is very verbose.So I started writing abstractions for containers, padding... At some point, I realized that I was just reimplementing flexbox. But it was a worst implementation of flexbox because it didn't properly work with text and was way slower.
The other difficulty is that you need references to all those elements. In order to tell where an element is, you need a reference to your parent. This model doesn't work well with React components where you only shouldn't know about your parent.
## Where it shines
The places where constraint solver shines is when you have a wysiwyg element builder. You have a reference to all the elements as they are visible on-screen so it's very easy to link them and you can show 4 inputs for each constraint.
This is very useful for xcode interface builder and would be a good fit for designer tools like photoshop.
Hopefully this gives some light around why we didn't proceed with cassowary :)
You had a really inspiring use of fuzz testing and TDD. You used a hilarious technique to implement it in several languages at once. And I heard a rumor you did it all over your paternity leave?!
That sounds like "strength" was probably the wrong approach. Why not require the developer to simply resolve conflicts? Your set of inequalities are a basic type system and you tried to resolve your type errors by layering some secondary weird "overriding" type system over top. Better to just resolve the errors from the get-go, and when it compiles, you know it will run correctly.
> The most annoying instance is line breaking. You cannot encode how lines are going to break as a set of linear inequations.
Is this discussed anywhere in more detail? It doesn't sound right to me, unless I'm misunderstanding what you mean here.
2) The height of a text is not a linear function based on the width of the container. You can't say, the height of the text is 10px * number of characters * width of the container.
Instead, if you add a single more character that makes it go to the next line it's going to add a single lineheight.
So, you can't encode this inside of the simplex and you need to do it as a separate pass.
It sounds like a limited set of discontinuous functions are needed, like how media queries are used in CSS. The constraints to satisfy are defined by a set of top-level discontinuous functions on environmental parameters, but the set is always fixed so it's pretty simple to detect when you need to switch to a different set of constraints. Wouldn't that suffice?
> The height of a text is not a linear function based on the width of the container. You can't say, the height of the text is 10px * number of characters * width of the container.
For simplicity, let's take the easiest case of a fixed width font and we'll hard wrap at X characters, regardless of whitespace positions. The number of lines L and the height of the text H in px is then given by:
L = char_px_width * char_count / container_px_per_line
H = L * char_px_height
Agreed? If so, then that case isn't difficult, but difficulties arise when you want better wrapping behaviour based on whitespace with a non-fixed width font. I agree that doing it precisely with linear equations doesn't seem feasible, but it seems like we can closely approximate it to minimize the reflows needed to converge on the final result.Suppose we set char_px_height=the widest character of the typeface (ditto for char_px_height) so we overestimate the dimensions needed. A quick google search suggests that the average word length for ordinary English is around 5 characters. So with avg_word_length=5, the above equation changes to something like:
L = char_px_width * avg_word_length * ceiling(char_count / avg_word_length) / container_px_per_line
This should miss the actual number of lines needed at most by 1, except when dealing with highly irregular text. Then again, the avg_word_length can be constantly adjusted on the fly based on the reflows you have to do, so this should quickly converge too. Does this sound right?Edit: sorry, that last calculation is obviously wrong, I was rushing out the door. The idea is to estimate number of lines from the average nnumber of words that would fit per line.
I have been using it for some time and it is an huge step in the right direction.
A downside of Yoga seems to be its tooling, ConstraintLayout is very well integrated with Android Studio. Actually they created it hand in hand with a rewrite of its layout editor.
Actually, CL one of the reasons behind the creation of RL is to improve on RL : - remove the need to nest for complex layouts. Nesting has some intrinsic measure/layout overhead. CL solves this by allowing way more types of relative constraint. The only remaining reasons for manual ViewGroups are performances (still faster than any generalistic approach) or really deep customization.
- solve some of RL qwirks. There are a couple of behaviors which are surprising. CL streamline these corner cases.
- deeper layouting possibilities
- integrated with a better layout editor. By better, I mean something you might choose to use, unlike the previous layout editor.
CL is in beta right now, you can add it as an external lib (that way the android team can update it anytime they want). The layout itself is already useable in production, the layout editor is where there are still some potential bugs.
The previous layout editor was pretty much unusable. Even though XML is ugly it is still efficient to work with (especially since the IDE auto completes all the cruft), so almost nobody was using the old layout editor.
The new one is still in beta and has some rough edges but it sounds like this will actually be useable and maybe even faster than editing the XML in some cases.