ConstraintLayout, Chains and wrap_content
Let’s pretend you are creating a layout for a list item. Let’s also pretend that your design calls for three buttons in a column, centered horizontally and with a little space in between them. Finally, let’s pretend you’ve heard how cool and fast ConstraintLayout is, and you decide to use it.
So you create a new layout file, make ConstraintLayout the root and drag thee buttons onto it, roughly where you want them to be placed. You now have something like this:
So far so good. You select all three buttons, right-click and choose “Center Horizontally in Parent”. There, easy. Now comes the tricky bit. How do you ‘pack’ them all together in the vertical middle of the layout?
A more advances ConstraintLayout user will immediately suggest creating a Chain and making it ‘packed’. And indeed, it works perfectly. The buttons seem a bit too close together, though, so you give them all 16 dips of margin on each side. Now they have room to breathe!
But hang on a second! This is a list item, isn’t it? It can’t just take up the entire height of the screen, can it? We need to shrink it! That should be easy, just select the ConstraintLayout, change its height to ‘wrap_content’, and… oh no.
Disaster. Not only is the bottom margin gone, the bottom button is cut off! How do we make it right?
Fortunately, the solution is easy — get rid of the chain. Constrain each button from the top only, save for the bottom one which you also pin to the bottom. Now just remember to increase the top margins, since the bottom ones no longer apply (margins only work on edges that are constrains applied).
So what did we learn today?
We learned that Chains in ConstraintLayout have a slightly unexpected, and as of now undocumented, behaviour. They work fine when you want to distribute unused space, but backfire spectacularly when you’re trying to claim more of it.
We also learned to remember this rule:
Only constrain your views from both sides when that axis is set to ‘match_parent’ — otherwise just from the top/start.
As a final note — this happens on ConstraintLayout 1.0.2 and might be fixed in later versions. Also, I haven’t found an explanation for this in the official docs, but if you know more about it I’d be glad to know!