Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Event Listener Data Binding for ViewPager

Is it possible to bind a handler for setOnPageChangeListener to a ViewPager in XML file with the Android Binding functionality?

The demos show onClick events but I am curious as to how much event functionality I can implement with it. Any links on the capabilities of Data Binding would be great as well. Thanks.

Hypothetical example:

example_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

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

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:onPageChangeListener="@{handlers.pageChanged}" />
</layout>

Handler.java

package com.example.viewmodels;

import android.view.View;

public class Handlers {
    public void pageChanged(View view){}
}

The compilation error is:

Error:(62) No resource identifier found for attribute 'onPageChangeListener' in package 'android'

like image 378
running-codebase Avatar asked Jun 03 '16 05:06

running-codebase


People also ask

What is 2 way Data Binding in Android?

Stay organized with collections Save and categorize content based on your preferences. The @={} notation, which importantly includes the "=" sign, receives data changes to the property and listen to user updates at the same time.

Which is the correct way to reference bound data in the XML layout?

Layout Binding expressions Expressions in the XML layout files are assigned to a value of the attribute properties using the “ @{} " syntax. We just need to use the basic syntax @{} in an assignment expression.

How would you enable view Binding for a module in your application so you can reference views from layout files without using Findviewbyid?

To enable view binding, configure viewBinding in your module-level build. gradle file. Once enabled for a project, view binding will generate a binding class for all of your layouts automatically. You don't have to make changes to your XML — it'll automatically work with your existing layouts.


2 Answers

It is possible to do this. You need to implement a custom binding adapter because there is no BindingAdapter classes predefined for View classes from Android support libraries.

For how to implement the custom adapter you may read this.

The code should be something like the below, I haven't tested them thoroughly:

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:onPageChangeListener="@{handlers}" />

Your BindingAapter code:

@BindingAdapter("onPageChangeListener")
public static void setOnPageChangeListener(ViewPager viewPager, ViewPager.OnPageChangeListener listener) {
    Log.i("setOnPageChangeListener");

    // clear listeners first avoid adding duplicate listener upon calling notify update related code
    viewPager.clearOnPageChangeListeners();
    viewPager.addOnPageChangeListener(listener);
}

P.S. Your handler class being passed should implement ViewPager.OnPageChangeListener.

like image 171
chubao Avatar answered Oct 21 '22 18:10

chubao


Instead of OnPageChangeListener, you can use SimpleOnPageChangeListener and only override the method you're interested in:

@BindingAdapter("onPageChanged")
@JvmStatic
fun addPageChangedListener(viewPager: ViewPager, listener: OnPageChanged) {
    viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
        override fun onPageSelected(position: Int) {
            listener.onPageChanged(position)
        }
    })
}

interface OnPageChanged {
    fun onPageChanged(position: Int)
}

Layout:

<androidx.viewpager.widget.ViewPager
    app:onPageChanged="@{viewModel::handlePageChanged}">

Handler:

fun handlePageChanged(position: Int) {
    println("Page changed: $position")
}

As others have pointed out, you may want to be careful not to attach duplicate listeners.

like image 30
Big McLargeHuge Avatar answered Oct 21 '22 19:10

Big McLargeHuge