Carloss Sessa of 50 Android Hacks starts off with an interesting problem: how to center a button that is 50% of its parent width?
It’s easy to center a generic button. Using
FrameLayout, one could simply set the appropriate layout gravity:
But how to set the button width to 50% of its parent? I decided to create a custom
When creating custom views, you usually want to override some standard methods the framework uses. There are two I could consider in this case:
onMeasuredetermines the size requirements for this view and all of its children
onLayoutassigns a size and position to all of its children.
Because the parent layout already provides the position I’m after,
onMeasure will suffice.
onMeasure is straightforward: after invoking
super, which provides initial measurements, we get the parent width, halve it and apply the result. Then, we tell the XML layout to use it:
It works! However, there’s a slight hiccup - the text is not centered. Applying
android:gravity="center" doesn’t work:
super.onMeasure! A closer look at the source code reveals a simple text like “Button” is drawn with the help of a
BoringLayout. The layout is also responsible for positioning the text based on the available height, width and gravity.
Since I only change the width after
super.onMeasure, it has no effect to the initially calculated dimensions and position.
Enter MeasureSpec. Scary documentation hides its simple nature: the three modes,
EXACTLY, are a rough translation of the familiar
match_parent and a specific size, e.g.
Two encoded values of the
heightMeasureSpec present the
MeasureSpec values from its parent View. This is handy, we can easily extract the parent width from it:
If we could modify the
widthMeasureSpec to be half its parent width, and pass it to the
super.onMeasure, our work would be done. Fortunately, that’s easy: