Android Data Binding Tips
Tip 1: Create a Visibility Binding Adapter

I've been working with Android Data Binding for a few months now. In that time, I have discovered a few patterns and practices that have made development with Data Binding successful and ...dare I say... fun!

On occasion, I will share them here on the blog. In this first installment, we'll create a binding adapter to control a view elements visibility.

Android Fundamentals: Data Binding

A soup-to-nuts exploration of the Android Data Binding library.

Android Data Binding expressions are powerful. Nevertheless, sometimes the expressions can get pretty ugly. One common expression you may find yourself doing is showing and hiding a view based on a variable defined in the data section of the layout. If you have used data binding before, you may have written something like this:

<layout>
<data>
<import type="android.view.View"/>
<variable name="show" type="Boolean"/>
</data>

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="@{show ? View.VISIBLE : View.GONE}"/>

</layout>

I, for one, really hate typing this out. First, I need to remember to import the android.view.View type. On top of that, I need to ensure that I get the constants capitalized - Android Studio does not support autocomplete in binding expressions. Ugh!

A More Elegant Syntax

When declaring visibility, I either toggle between VISIBLE and GONE or VISIBLE and INVISIBLE, but never toggle among all three. Therefore, I would prefer to declare the state as a boolean and have the element react accordingly. Because the hidden state is either GONE or INVISIBLE, I can use that state as the attribute name. In the following snippet, I declare the attribute as app:isGone with a data-bound value of !show. I pass the ! to invert the boolean’s value - in this attribute, a true value will hide the view.

<layout>
<data>
<variable name="show" type="Boolean"/>
</data>

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:isGone="@{!show}" />

</layout>

Binding Adapters to the Rescue

With the preferred syntax in place, I can create a binding adapter. The adapter can be added to any class; however, I would add this type of adapter to a ViewBindingAdapters class in a core namespace to follow the Data Binding library’s convention.

As a review, to create a binding adapter, you create a static void method with a @BindingAdapter annotation. In its simplest form, the annotation contains a value to match the attribute we want to bind to. Because we are using an attribute that will not be namespaced as android:*, we omit the namespace. The method parameters are the view type we want to adapt and the value expected from the attribute.

// ViewBindingAdapters.java

@BindingAdapter("isGone")
public static void setIsGone(View view, boolean hide){
view.setVisibility(hide ? View.GONE : View.VISIBLE);
}

@BindingAdapter("isInvisible")
public static void setIsInvisible(View view, boolean hide){
view.setVisibility(hide ? View.INVISIBLE : View.VISIBLE);
}

Now, I no longer need to type that ternary expression in my layouts. When using the attribute, remember that a true expression will signal the adapter to hide your view (instead of show it). Hopefully, this will be useful for you too! Let me know what you think!


I cover creating custom data binding adapters in my course on Pluralsight. Be sure to check it out!
comments powered by Disqus