In my user interface, I have a fragment with a RelativeLayout. At the bottom of this RelativeLayout, I have two buttons: one should be on the left, the other on the right, with empty space between them. The left one has static text (but because the app will be translated, I don’t know what width it will be). The text in the right one can change arbitrarily.
Since I already have a RelativeLayout, I started out trying to lay them out inside the RelativeLayout like this:
<Button
android:id="@+id/button_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="@string/left" />
<Button
android:id="@+id/button_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/right" />
But this has the problem that if the text in the right-hand button is too long, it will overlap the left-hand button.
I next tried to constrain the left-hand edge of the right-hand button by adding android:layout_toRightOf="@+id/button_left", but with this, the right-hand button would always fill the available width. When the text in the right-hand button is short, I want it to shrink to leave a gap between it and the left-hand button.
I next tried to use a LinearLayout, so I could set layout_gravity on the buttons, like this:
<LinearLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<Button
android:id="@+id/button_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/left" />
<Button
android:id="@+id/button_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:drawableLeft="@drawable/pass"
android:text="@string/right" />
</LinearLayout>
Still no joy. I expected this to work, but the right-hand button stays just to the right of the left-hand button, instead of sticking to the right edge of the screen. I can see in the layout editor that the LinearLayout correctly fills the width of the screen, but the button stubbornly stays next to its friend.
I tried adding android:layout_weight="1" to the right-hand button too, but again, that made it always expand to fill the available space.
Next, I tried to add an empty View between the buttons, to expand and force the right button to the right, like this:
<LinearLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<Button
android:id="@+id/button_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/left" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="@+id/button_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/right" />
</LinearLayout>
This works fine when the text is short, just like my original RelativeLayout did, but now when the text on the right-hand button is long, its width is limited by the width of the screen, not the available space, so it extends off the right-hand edge of the screen. Again, I can see in the layout editor that the LinearLayout has the correct width, but the button is extending ourside its parent’s bounds. This happens even if the button has android:layout_width="match_parent". Oddly enough, increasing the layout_gravity on the right-hand button makes it smaller until it fits inside the available space, but of course that also makes it fill the space when the text is small.
I can’t believe it’s this hard to get this right. I’ve seen half a dozen similar questions on SO, but they all have easy workarounds. If the button text is fixed, you can set the margin to a fixed width by hand. If the expanding widget is a TextView instead of a Button, you can just let it expand and use android:gravity to move the text inside the widget, but you can’t do that with a button because the background and borders are visible on the screen.
It turns out that adding the LinearLayout was the wrong approach. Using
android:layout_toRightOf="@+id/button_left" android:layout_alignParentRight="true"works fine with a TextView, because that can soak up the available space without changing its appearance. Instead of trying to change the layout, I just need to use something that can expand to fill the available space and contain the Button: a FrameLayout. Here’s the working code, which still goes inside my root RelativeLayout:Now, the FrameLayout always takes up all the space to the right of the left-hand button, and lays out the right-hand button inside that space using
android:layout_gravity="right".This answer only adds one extra layout, but if someone has a way to do it only using the existing RelativeLayout, to minimise the number of ViewGroups in the layout, I’ll accept that as a solution.