12

I created a custom compound view - the view loads, no crashes, so far so good.

Now, i plan to use this view MANY MANY times in my app, so the view needs a style.

I declared a styleable for it in my attr.xml file

  <declare-styleable name="MyCustomView">

        <attr name="ff_label" format="string" />
        <attr name="ff_fieldText" format="string" />
    </declare-styleable>

    <declare-styleable name="MyCustomViewStyle">
        <attr name="customViewStyle" format="reference" />
    </declare-styleable>

Then i went to my theme file and wrote this inside

<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">

    <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    //bunch of other stuff
    <item name="customViewStyle">@style/customViewStyle</item>
</style>

then in my android manifest i declared

<application
        android:name="com.my.app.App"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

then in my styles.xml file i wrote

   <style name="customViewStyleStyle" parent="@android:style/Widget.EditText">
        <item name="android:paddingBottom">@dimen/space_between_adjacent_widgets_vertical</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="ff_label">@string/default_label_text</item>
        <item name="ff_fieldText">@string/default_label_text</item>
    </style>

My problem : My OWN attributes are recognised just fine.
Why are the attributes labeled "android:..." ignored ?

MyCustomView.java

public MyCustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
    initAttributes(context, attrs, R.attr.customViewStyle);
}

public MyCustomView(Context context) {
    super(context);
    initAttributes(context, null, R.attr.customViewStyle);
}

private void initAttributes(Context context, AttributeSet attrs, int defStyle) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.custom_view, this, true);
    label = (TextView) findViewById(R.id.label);
    formField = (EditText) findViewById(R.id.formField);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle,0);

    if (a.hasValue(R.styleable.MyCustomView_ff_label)) {
        labelText = a.getString(R.styleable.MyCustomView_ff_label);
        label.setText(labelText);
    }


    if (a.hasValue(R.styleable.MyCustomView_ff_fieldText)) {
        fieldText = a.getString(R.styleable.MyCustomView_ff_fieldText);
        field.setHint(fieldText);
    }


    a.recycle();
}

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.my.app"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

   <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
          />

    <include layout="@layout/layout_set_default" />

</TableLayout>

The default height of 1 view is about 30 dp - > and i can't use a list view for it. Its supposed to have 10dp padding between each view

Lena Bru
  • 12,299
  • 9
  • 53
  • 109
  • Written article on [styling custom views in Android](http://onetouchcode.com/2016/11/25/styling-custom-views-android/). – Shailendra Nov 27 '16 at 05:40

1 Answers1

10

You have to change the code of MyCustomView like here:

    ...
    public MyCustomView(Context context, AttributeSet attrs) {
            //Called by Android if <com.my.app.MyCustomView/> is in layout xml file without style attribute.
            //So we need to call MyCustomView(Context context, AttributeSet attrs, int defStyle) 
            // with R.attr.customViewStyle. Thus R.attr.customViewStyle is default style for MyCustomView.
            this(context, attrs, R.attr.customViewStyle);
    }

    public MyCustomView(Context context) {
            this(context, null);
    }

    public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
            //Called by Android if <com.my.app.MyCustomView/> is in layout xml with style attribute
            // For example:
            //         <com.my.app.MyCustomView
            //                android:layout_width="match_parent"
            //                android:layout_height="wrap_content"
            //                style="@style/customViewStyleStyle"
            //                />
            //
            super(context, attrs, defStyle);
            initAttributes(context, attrs, defStyle);
    }
    ...

Then you can use style attribute in layout.xml and customViewStyle would be also the default style for MyCustomView. The same as textViewStyle is default style for TextView

    <com.my.app.MyCustomView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/customViewStyleStyle"
      />

Previously you had the constructor:

public MyCustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
    initAttributes(context, attrs, R.attr.customViewStyle);
}

As you can see you pass R.attr.customViewStyle to initAttributes() method but don't pass it to parent constructor.

olegr
  • 1,640
  • 16
  • 20
  • I added a theme, and i wrote that i added the theme to the application I wrote that "my own" attributes are recognized. what is ignored is "android:bottomPadding" why ? – Lena Bru Jun 14 '14 at 12:12
  • The post shows step by step how i added the them - the theme works. just that if i put in the custom style "normal" android attributes, they are ignored...... – Lena Bru Jun 14 '14 at 12:13
  • Your post is very informative, but could you add your layout xml and activity code? – olegr Jun 14 '14 at 12:33
  • I mean that part where you are using MyCustomView. I think the problem is there. Because I've made application from scratch using your resources and padding works fine. But certainly I used my own activity.xml and Activity class. – olegr Jun 14 '14 at 12:37
  • See my edited answer. Your custom attributes were fetched from custom style because MyCustomView has TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle,0); But default inflator doesn't know that you wnt to apply customViewStyleStyle to com.my.app.MyCustomView – olegr Jun 14 '14 at 16:22
  • I specifically did NOT want to add style attributes because i am using a theme for the entire application, and not for just one widget - my custom style via the theme IS recognised. It is not the problem. – Lena Bru Jun 14 '14 at 19:54
  • please see my "MyCustomView.java" that is exactly what is written there – Lena Bru Jun 15 '14 at 07:03
  • No it has differences) Just copy past and try) – olegr Jun 15 '14 at 07:54
  • can you explain to me the difference? i dont see it. but it did work – Lena Bru Jun 15 '14 at 12:26
  • i m also experiencing this problem as my margin attribute is ignoring and i have tried your solution but no luck – Burhan Khanzada Mar 26 '20 at 23:18