I think I may have found a bug in the way layout_margin
works on buttons. It can be summarized as button margins are not taken into account when measuring. As a result, their parent ViewGroup
measures itself slightly too small. When the buttons are finally drawn, there isn't enough room and they're forced to wrap or ellipsize their text. This happens even when there's plenty of room in the buttons' grandparent for the buttons' parent to be larger. The problem exists whether I set the layout_margin
in the button's style or on the button itself. I don't know if this affects other kinds of views.
Is this a known issue? Does any workaround exist, other than not using margins on buttons? (Or am I simply doing something wrong?)
I found an unanswered question from about a year ago that says layout_margin
does not work at all in custom button styles. It actually works for me the way the asker of that question expected it to, at least in the sense that the buttons do have the specified margin. So maybe Google "fixed" it recently and the fix overlooked something.
This fragment layout demonstrates the issue. It looks fine by itself in the editor. The specified button style has a layout_margin
of 3dp
.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/userField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="8"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:hint="@string/hint_user" />
<EditText
android:id="@+id/passwordField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/userField"
android:layout_alignLeft="@id/userField"
android:layout_alignRight="@id/userField"
android:inputType="textPassword"
android:fontFamily="sans-serif"
android:hint="@string/hint_password" />
<Button
android:id="@+id/loginButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/userField"
android:layout_centerVertical="true"
style="@style/button_blue"
android:text="@string/login" />
</RelativeLayout>
But when this fragment is placed inside another layout, the fragment's width is apparently calculated incorrectly.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/fragment"
android:name="com.example.MyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
tools:layout="@layout/fragment_login" />
</RelativeLayout>
The text wraps mid-word because I used a non-breaking space (\u00A0
) in the button text. With a normal space it wraps at the word boundary. The problem disappears if I remove the layout_margin
from the button style.
Edit: Here's a stand-alone layout that demonstrates the problem. The problem is always present in the WYSIWYG editor, SDK 21. On real devices, the bug manifests on 2.3.6 and 4.0.4 but not 4.4.1 or 5.0.1.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.chalcodes.marginbug.MainActivity" >
<RelativeLayout
android:id="@+id/buttonLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="Button" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:layout_toRightOf="@id/button1"
android:text="Button" />
</RelativeLayout>
</RelativeLayout>
Edit 2: Following up on corsair992's comment, I updated AS to the latest version (1.2 beta 3) and pasted my standalone example above. This does reproduce the problem. But strangely, the problem disappears when I change the preview orientation from portrait to landscape. Stranger still, the problem does not come back when I return to portrait! And if I restart AS, it again renders my layout incorrectly the first time, then renders it correctly after rotation. Eclipse always renders the layout incorrectly.
I've noticed that Android Studio's WYSIWYG editor caches things more aggressively than Eclipse's does. In Eclipse I can immediately see changes to custom views, but AS stubbornly hangs on to old renderings of custom views after a clean & rebuild, or even after a restart. So maybe AS is caching some info about the layout which helps it render correctly the second time. But maybe this is just masking the bug.