30

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>
Groppe
  • 3,819
  • 12
  • 44
  • 68

3 Answers3

60

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.

Community
  • 1
  • 1
Groppe
  • 3,819
  • 12
  • 44
  • 68
  • 10
    W...T...F?? why? whY? WHY?!?! ... please forgive me... i'm losing my mind with all the quirks of Android development. – pbristow Feb 26 '16 at 15:52
  • 1
    This answer is somewhat unsatisfactory - layout margins are still not applied even when the parent ViewGroup and the child View are in the same layout xml file. In this case the inflater *does* know about the concrete type of the parent ViewGroup (because it just inflated it) and also knows the style to apply (because other style attributes are applied). – Robert Tuck Oct 14 '16 at 11:42
1

You arent using the correct theme name in your Manifest. Try changing it to:

<application
     android:icon="@drawable/ic_launcher"
     android:label="@string/app_name"
     android:theme="@style/MyTheme" >
James McCracken
  • 15,488
  • 5
  • 54
  • 62
  • Sorry, that was a typo in the post on my part. They are the same in my actual project. Good suggestion though :/ – Groppe Nov 01 '12 at 12:14
0

Just in case it is useful for others, I'd like bring the answer by Oliv to another SO question here. I was trying to add margins to all buttons and found layout_margin does not work.

The theme:

<style name="FooThemeStyle" parent="Base.Theme.AppCompat">
    <item name="android:buttonStyle">@style/FooButton</item>
    <item name="buttonStyle">@style/FooButton</item>
</style>

The button style:

<style name="FooButton" parent="Widget.AppCompat.Button">
    <item name="android:background">@drawable/button_background</item>
</style>

Here is button_background.xml where the answer by Oliv to another SO question is used to set the margin to 2dp: :

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
          ...
        </selector>
    </item>
</layer-list>
Hong
  • 17,643
  • 21
  • 81
  • 142