Android Data Binding: visibility on include tag
AndroidAndroid DatabindingAndroid Problem Overview
As per http://developer.android.com/tools/data-binding/guide.html#imports, we can have such simple expressions in visibility:
<TextView
..
android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
But when I try to do the same in an include
tag, like so:
<include
android:id="@+id/image_layout"
layout="@layout/image_layout"
android:visibility="@{notification.notifType == 0 ? View.VISIBLE : View.GONE}"/>
Then Studio not only shows the expression in red, but upon building it gives the following error in the auto-generated binding class:
> Error:(138, 29) error: cannot find symbol method setVisibility(int)
Here's where the error occurs in the auto-generated binding class
// batch finished
if ((dirtyFlags & 0x3L) != 0) {
// api target 1
this.imageLayout.setVisibility(NotifTypeNotificatio1);
}
imageLayout.executePendingBindings();
Android Solutions
Solution 1 - Android
I imagine what you are trying to do would look something like this:
In the layout you are including, specify a boolean variable and bind it to the desired view's visibility
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="isVisible"
type="boolean"/>
</data>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{isVisible ? View.VISIBLE : View.GONE}"/>
</layout>
Then In your calling layout bind your value
<include
android:id="@+id/image_layout"
layout="@layout/image_layout"
bind:isVisible="@{notification.notifType == 0}"/>
Solution 2 - Android
Try:
this.imageLayout.getRoot().setVisibility(NotifTypeNotificatio1);
Solution 3 - Android
You are able to pass all necessary parameters from parent xml into included xml via "http://schemas.android.com/apk/res-auto"
namespace.
The syntax is <res-auto_namespace>:<variable_name>
e.g. app:isVisible
For example
<?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">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/include_user_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:isVisible="@{true}" />
</android.support.design.widget.CoordinatorLayout>
</layout>
include_user_image.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable
name="isVisible"
type="boolean" />
</data>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{isVisible ? View.VISIBLE : View.GONE}" />
</layout>
Solution 4 - Android
This is a bit late, but I have run across this recently.
I believe this is actually a bug in the Data Binding compiler as it is possible to set android:visibility
attribute on <include>
tag directly (ie. without Databinding).
Solution 5 - Android
A better way.
On the top layout, declare the boolean or an observable field whose value toggle the visibility of the included layout. Then remember to give the included layout an id else it wont work
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View"/>
<variable
name="show"
type="Boolean" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="@color/colorPrimary">
<include layout="@layout/progress"
android:id="@+id/progress"
android:visibility="@{show?View.VISIBLE:View.GONE}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Solution 6 - Android
Best Way
- You can directly pass
Integer
value ofvisibility
like. - You can set default value of
visibility
also by settingdefault=gone
in binding.
For example this is included_layout.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="visibility"
type="int"/>
</data>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{visibility, default=gone}"
/>
</layout>
and use like
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
</data>
<include
android:id="@+id/included_layout"
layout="@layout/included_layout"
app:visibility="@{View.VISIBLE}"/>
</layout>
Solution 7 - Android
Data binding is not needed, instead get a reference to the root view of the <include>
layout and set its visibility. For example,
binding.myIncludeLayout.root.visibility = View.VISIBLE
Solution 8 - Android
To provide visibility in include tag, you need to convert the included layout to data-binding even though no data is passed on included layout.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
</data>
<LinearLayout
android:id="@+id/myblock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/main_bg_alternative"
android:orientation="vertical"
android:paddingTop="15dp"
android:paddingBottom="20dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:text="@string/hello"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
and on your activity XML, you can use visibility as
<include
layout="@layout/include_body"
android:visibility="@{results.size()>0 ? View.VISIBLE : View.GONE, default=gone}"
tools:visibility="visible" />
Solution 9 - Android
I've bumped into the same error. Databinding was working with every view element except the included layouts.
There's no need to have a workaround for this, what I did is I've surrounded the included layout's root with <layout>
tag and put a collapsed <data/>
tag in there too - initialised the included layout for databinding.
Voila! It worked.
Solution 10 - Android
This is the direct approach, without having to pass the variable inside the included layout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
layout="@layout/layout_errors"
android:visibility="@{isVisible ? 0:1 }"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
The above code was all I needed
The interesting thing is if I remove the above ternary operator and simplify it like this,
<include
layout="@layout/layout_errors"
android:visibility="@{isVisible}"
/>
with addition of an BindingAdapter class with following method,
@BindingAdapter("android:visibility")
public static void setVisibility(View view, boolean isVisible) {
view.setVisibility(isVisible ? View.VISIBLE : View.GONE);
}
Boom! the OP error invades my entire BuildOutput trace, interesting world of Android
Solution 11 - Android
Thank to everybody, you help me a lot. Your answers were part of my succes on this trouble.
We wanted to set visibility of an image view, that was also target of some animation. The Motion Scene was taking the management of the visibility. Set the motion property app:visibilityMode to "ignore" solve everything.
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="@+id/expanded">
<!-- ... -->
<Constraint
android:id="@+id/myImageViewId"
app:visibilityMode="ignore"/>
</ConstraintSet>
<!-- ... -->
</MotionScene>
Solution 12 - Android
You can find the included layout by its id and hide it using the visibility
attribute.
For example in Kotlin,
binding.root.findViewById<CardView>(R.id.layout_inclulded).visibility = View.GONE
where,
root
is the default attribute for the root element in the parent layout.
CardView
is the root element of the included layout in my case.
R.id.layout_inclulded
is the id
of the included layout in the parent layout.