30

I'm trying to use databinding with custom views (a possible usage George Mount showed here).

One can't imagine building compound views without <merge> tag. However, in this situation databinding fails:

MyCompoundView class:

public class MyCompoundView extends RelativeLayout {

MyCompoundViewBinding binding;

public MyCompoundView (Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

private void init(Context context){
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    binding = MyCompoundViewBinding.inflate(inflater, this, true);
}

my_compound_view.xml: by app:isGone="@{!data.isViewVisible}" i hoped to control the visibility of the whole compound view

<?xml version="1.0" encoding="utf-8"?>

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

    <data>
        <variable name="data" type="com.example.MyViewModel"/>
    </data>

    <merge
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:isGone="@{!data.isViewVisible}">

        <ImageView
            android:id="@+id/image_image"
            android:layout_width="60dp"
            android:layout_height="60dp"
            app:imageUrl="@{data.imagePhotoUrl}"/>

         <!-- tons of other views-->

    </merge>

</layout>

The compiler errors:

Error:(13) No resource identifier found for attribute 'isGone' in package 'com.example'
Error:(17, 21) No resource type specified (at 'isGone' with value '@{!data.isViewVisible}').

I have all needed @BindingAdapter methods. Now I inherit the view from FrameLayout and use <RelativeLayout> instead of <merge> - and it works. But I have extra nested layout.

Question: merge attrs are ignored. Is there any way to workaround that?

Android Studio 1.5.1 stable

Gradle plugin com.android.tools.build:gradle:1.5.0

Community
  • 1
  • 1
Dmitry Gryazin
  • 933
  • 1
  • 11
  • 24

2 Answers2

18

There is no merge object after inflation, so there is nothing to assign values to with a merge tag. I can't think of any binding tag that will work on merge.

You can assign the tag to the root element and use the BindingAdapter to do what you want.

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

    <data>
        <variable name="data" type="com.example.MyViewModel"/>
    </data>

    <merge
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            app:isGone="@{!data.isViewVisible}"
            android:id="@+id/image_image"
            android:layout_width="60dp"
            android:layout_height="60dp"
            app:imageUrl="@{data.imagePhotoUrl}"/>
         <!-- tons of other views-->
    </merge>
</layout>

If you want to do something with the Binding class itself, you can use the DataBindingUtil to find the object from the View.

@BindingAdapter("isGone")
public static void setGone(View view, boolean isGone) {
    ViewDataBinding binding = DataBindingUtil.findBinding(view);
    //... do what you want with the binding.
}
George Mount
  • 20,708
  • 2
  • 73
  • 61
  • 2
    Exactly Android developers mentioned about it in [documentation](https://developer.android.com/topic/libraries/data-binding/index.html#layout_details) – MrOnyszko Aug 23 '16 at 21:00
  • Could you elaborate your advice with some code? Thank you :) – DarkLeafyGreen Apr 11 '17 at 07:36
  • 6
    Hello, I can't get the merge tag to work. It shows the error `Element merge is not allowed here`. See: https://pastebin.com/QhQKYN71 – Thomas Vos Jun 03 '17 at 14:57
  • Here, `merge is not allowed here` is just a warning but it's [a known bug](https://issuetracker.google.com/issues/37150098) – Giszmo Oct 10 '18 at 16:10
3

Actually you can use <merge> tag inside <include> and do data binding.

Ex:

incl_button.xml

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

        <Button android:id="btn"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="Click"
         />

    </merge>
</layout>

fragment_example.xml

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            layout="@layout/incl_button"
            android:id="@+id/layout_btn" />

    </LinearLayout>
</layout>

ExampleFragment.kt

binding.layoutBtn.btn.setOnClickListener{
   //...
}
user158
  • 12,852
  • 7
  • 62
  • 94