Android - margins specified in custom style not taking effect

Groppe picture Groppe · Oct 31, 2012 · Viewed 17.6k times · Source

I wish to have the default margin for EditText's be 10dp. Therefore, in my styles.xml file I set up the following:

<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <style name="MyTheme" parent="android:style/Theme.NoTitleBar">
        <item name="android:editTextStyle">@style/edit_text_default</item>
    </style>

    <style name="edit_text_default" parent="android:style/Widget.EditText">
        <item name="android:layout_margin">10dp</item>
    </style>

</resources>

Then in AndroidManifest.xml, I set the applications theme to the one I defined:

<application
     android:icon="@drawable/ic_launcher"
     android:label="@string/app_name"
     android:theme="@style/MyTheme" >
...

The "No Title Bar" aspect of the theme is working. However, the default margin for EditText's is not, it is still filling the parent. Here is my table view:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#FFFFFF" >
    <TableRow>
        <EditText android:hint="@string/last_name" />
    </TableRow>
    <TableRow>
        <EditText android:hint="@string/first_name" />
    </TableRow>
</TableLayout>

Answer

Groppe picture Groppe · Nov 13, 2012

Short Answer: If you are specifying layout_margin in a custom style, this style must be explicitly applied to each individual view that you wish to have the specified margin (as seen in the code sample below). Including this style in a theme and applying it to your application or an activity will not work.

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#FFFFFF" >
    <TableRow>
        <EditText android:hint="@string/last_name" style="@style/edit_text_default" />
    </TableRow>
    <TableRow>
        <EditText android:hint="@string/first_name" style="@style/edit_text_default" />
    </TableRow>
</TableLayout>

Explanation: Attributes which begin with layout_ are LayoutParams, or one of its subclasses (e.g. MarginLayoutParams). LayoutParams are used by views to tell their parent ViewGroup how they want to be laid out. Each and every ViewGroup class implements a nested class that extends ViewGroup.LayoutParams. Therefore, LayoutParams are specific to the ViewGroup's type. What this means is that while a TableLayout and a LinearLayout may both have layout_margin as one of it's LayoutParams, they are considered to be completely different attributes.

So layout_margin is not just general attribute that can be applied anywhere. It must be applied within the context of a ViewGroup that specifically defines it as a valid argument. A view must be aware of the type of its parent ViewGroup when LayoutParams are applied.

Specifying layout_margin in a style, including that style in a theme, and attempting to apply that theme to an application/activity will result in the layout attributes being dropped, because no ViewGroup parent has been specified yet and so the arguments are invalid. However, applying the style to an EditText view that has been defined with a TableLayout works, because the parent ViewGroup (the TableLayout) is known.

Sources:

Android documentation on Layout Parameters.

Answer given to this question by Android framework engineer and StackOverflow user adamp.

Also, answer given to this question by StackOverflow user inazaruk.