15

According to this CommonsWare example I managed to get my RelativeLayout subclass to be merged with my layout described in a xml layout with merge root. My only concern is that I cannot describe my RelativeLayout parameters in xml.

My xml layout:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:my="http://schemas.android.com/apk/res/hu.someproject"
  android:layout_width="36dp"
  android:layout_height="wrap_content"
  android:layout_marginLeft="3dp"
  android:layout_marginRight="3dp"
  android:width="36dp" >

 <RelativeLayout
    android:id="@+id/upper_container"
    style="?pretty_style"
    android:layout_alignLeft="@+id/image_title"
    android:layout_alignParentTop="true"
    android:layout_alignRight="@+id/image_title"
    android:layout_centerHorizontal="true" >

    <View
        android:id="@+id/upper_indicator"
        android:layout_width="fill_parent"
        android:layout_height="5dp"
        android:layout_alignParentTop="true"
        android:background="@color/mycolor" />

    <TextView
        android:id="@+id/text_degree"
        style="?pretty_style"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="23°" />
</RelativeLayout>

<hu.MyView
    android:id="@+id/image_title"
    style="?my_image_title"
    android:layout_below="@+id/upper_container"
    android:layout_centerHorizontal="true"
    my:myColor="#2f8741"/>

I think the problem is that merge happens to the children of the merge tag, and not the merge itself. Any idea how can I get my parameters in the merge to affect my RelativeLayout?

My RelativeLayout subclass, without package declaration and imports:

public class MyRelativeLayoutSubclass extends RelativeLayout {

    public MyRelativeLayoutSubclass(Context context) {
        super(context);

        initTile(null);
    }

    public MyRelativeLayoutSubclass(Context context, AttributeSet attrs) {
        super(context, attrs);

        initTile(attrs);
    }

    public MyRelativeLayoutSubclass(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initTile(attrs);
    }

    private void initTile(Object object) {
        final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_great_little_layout, this, true);
    }
}

I know I can add everything to a LayoutParams, and then add my MyRelativeLayoutSubclass with that LayoutParams, but I would like escape that, that's a lot of unnecessary code.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Mate Gulyas
  • 609
  • 2
  • 8
  • 22

2 Answers2

22

I think the problem is that merge happens to the children of the merge tag, and not the merge itself.

AFAIK, you are correct. <merge> is a placeholder, not a ViewGroup.

I know I can add everything to a LayoutParams, and then add my MyRelativeLayoutSubclass with that LayoutParams, but I would like escape that, that's a lot of unnecessary code.

Create an XML layout file containing a MyRelativeLayoutSubclass element, and put your attributes there. Then, inflate that layout.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • This is a very obvious solution, and I have no idea why I missed it. – Mate Gulyas Jan 21 '12 at 18:43
  • It doesn't let you have default attributes easily though. I have to re-enter them every time I use my custom component. – Timmmm Oct 29 '12 at 15:54
  • @Timmmm: `MyRelativeLayoutSubclass` can certainly have default values for attributes, used when it tries to read in the attributes from the XML (and fails to encounter them). – CommonsWare Oct 29 '12 at 15:56
  • Yeah but I mean you can't define them in XML (as attempted in the question) which would be the most ideal thing. – Timmmm Oct 29 '12 at 16:17
  • Well, the last advice cannot be applied, unfortunately, to ListView items. – Snicolas Nov 20 '14 at 21:48
  • @Snicolas: Custom views certainly can be used in `ListView` rows. – CommonsWare Nov 20 '14 at 22:02
  • 2
    @CommonsWare, for sure Mark, but what I mean is that as soon as you use merge, you cannot pass parameters via XML. If you have to wrap a custom view using merge into something else to achieve it, you loose the whole point of merge that is to reduce the view hierarchy depth. This optimization being especially useful for lists. As in listviews, you would instanciate a custom view using its code-constructor, it would not be possible to customize it via XML parameter anymore, only programmatically. Sorry I was not clear. Btw, I am at andev con too. Do we lunch together tomorrow ? – Snicolas Nov 21 '14 at 04:02
  • Although this is a working solution, it's far from ideal. You'd need two XML files for a single view, and naming gets hard. – Egor Jul 24 '18 at 15:40
3

Extracting all the attributes into Style was a solution for me. As a bonus it's screen-size dependent unlike the hard-coded attributes or Java-code. Maybe you can go further and put it into the Theme attributes.

<com.example.widget.MyCustomView
    android:id="@+id/my_custom_view"

    style="@style/MyCustomView.Default"/>
riwnodennyk
  • 8,140
  • 4
  • 35
  • 37