RecyclerView Databinding Item click
Asked Answered
B

2

9

I am trying to listen for row clicks (item clicks) on my recycler view from the Activity itself (not from adapter).

My Adapter so far looks like this:

public class ListMiestnostiAdapter extends RecyclerView.Adapter<ListMiestnostiAdapter.ViewHolder>{
    private List<Miestnost> data;

    // you provide access to all the views for a data item in a view holder
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewDataBinding binding;

        public ViewHolder(ViewDataBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        public void bind(Object obj){
            binding.setVariable(BR.obj, obj);
            binding.executePendingBindings();
        }
    }

    public ListMiestnostiAdapter(List<Miestnost> data) {
        this.data = data;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // create a new view
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        ActivityListMiestnostiRowBinding itemBinding = ActivityListMiestnostiRowBinding.inflate(inflater, parent,false);

        return new ViewHolder(itemBinding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Miestnost item = data.get(position);
        holder.bind(item);
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}

And my row layout like this:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="obj"
            type="com.example.com.projectname.Models.Miestnost" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?android:attr/selectableItemBackground"
        android:clickable="true"
        android:focusable="true"
        android:orientation="horizontal"
        android:paddingBottom="@dimen/row_padding_vertical"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/row_padding_vertical">

        <TextView
            android:id="@+id/txt_miestnost_row_nazov"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:text="@{obj.Name}"
            android:textSize="16dp" />
    </LinearLayout>
</layout>

As I have already mentioned I am trying to listen to item clicks, but not from Adapter itself (as other posts suggested), but from my Activity which holds this RecyclerView.

Is such action even possible? If yes, then any help would be highly appreciated as I could not find anything on google.

Bialystok answered 15/1, 2018 at 18:58 Comment(0)
K
15

You’ll first need an interface that specifies listener’s behavior. In this example, there is a sample model called ContentItem, so the click will return an item of that type:

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

The constructor will receive an object that implements this interface, along with the items to be rendered:

private final List<ContentItem> items;
private final OnItemClickListener listener;

public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
    this.items = items;
    this.listener = listener;
}

You could alternatively create a setOnItemClickListener method and assign it that way. Now, in onBindViewHolder the ViewHolder will receive the constructor in the custom bind method:

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(items.get(position), listener);
}

This is how this bind method looks:

public void bind(final ContentItem item, final OnItemClickListener listener) {
    ...
    itemView.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            listener.onItemClick(item);
        }
    });
}

Use it whenever you need it by creating a new adapter and the listener that will implement the behavior when an item is clicked. A simple example:

recycler.setAdapter(new ContentAdapter(
    items,
    new ContentAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(ContentItem item) {
            Toast.makeText(getContext(), "Item Clicked", Toast.LENGTH_LONG).show();
        }
    }));

Source

Kileykilgore answered 15/1, 2018 at 19:13 Comment(0)
S
2

To add to the answer provided by João Alvares Neto, we can call the OnItemClickListener directly from the layout.

In the variable tag, we can pass the OnItemClickListener and call it using the android:onClick property.

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

    <data>
        <variable
            name="storyClickListener"
            type="com.hoomanwe.zorro.ui.adapter.OnStoryClickListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="@{() -> storyClickListener.onStoryClick(item.id)}" />
</layout>

By this way, you can eliminate the following code from the solution provided by João Alvares Neto

public void bind(final ContentItem item, final OnItemClickListener listener) {
    itemView.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            listener.onItemClick(item);
        }
    });
}
Secondrate answered 4/7, 2020 at 14:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.