Detecting onClick in recycler view using data binding in android

为君一笑 提交于 2019-12-10 02:48:58

问题


  1. I am Referring to vogella-tutorial for databinding
  2. What i am trying to do: What is the best way to detect onClick in recycler view row for each Item using the dataBinding

activity_second.xml

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

    <data>
        <variable
            name="temp"
            type="com.vogella.android.databinding.TemperatureData" />
        <variable
            name="presenter"
            type="com.vogella.android.databinding.MainActivityPresenter"/>
    </data>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />
</layout>

rowlayout.xml

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

    <data>

        <variable
            name="obj"
            type="com.vogella.android.databinding.TemperatureData"
            />
    </data>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:padding="6dip"
        >

        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="6dip"
            android:contentDescription="TODO"
            android:src="@drawable/ic_listentry"
            />

        <TextView
            android:id="@+id/secondLine"
            android:layout_width="fill_parent"
            android:layout_height="26dip"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_toRightOf="@id/icon"
            android:ellipsize="marquee"
            android:text="@{obj.location}"
            android:textSize="12sp"
            android:maxLines="1"
        />

        <TextView
            android:id="@+id/firstLine"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/secondLine"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_alignWithParentIfMissing="true"
            android:layout_toRightOf="@id/icon"
            android:gravity="center_vertical"
            android:text="@{obj.celsius}"
            android:textSize="16sp"
            />

    </RelativeLayout>

</layout>

MyAdapter.java

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
        private List<TemperatureData> data;

        // Provide a reference to the views for each data item
        // Complex data items may need more than one view per item, and
        // you provide access to all the views for a data item in a view holder
        public class MyViewHolder extends RecyclerView.ViewHolder {
                // each data item is just a string in this case
                private final ViewDataBinding binding;

                public MyViewHolder(ViewDataBinding binding) {
                        super(binding.getRoot());
                        this.binding = binding;
                }
                public void bind(Object obj) {
                       binding.setVariable(BR.obj,obj);
                       binding.executePendingBindings();
                }
        }

        // Provide a suitable constructor (depends on the kind of dataset)
        public MyAdapter(List<TemperatureData> myDataset) {
                data = myDataset;
        }

        // Create new views (invoked by the layout manager)
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                // create a new view
                LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
                ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.rowlayout, parent, false);
                // set the view's size, margins, paddings and layout parameters
                return new MyViewHolder(binding);
        }

        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
                final TemperatureData temperatureData = data.get(position);
                holder.bind(temperatureData);

        }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            return data.size();
        }

}

MyAdapter.java

public class MyAdapter extends MyBaseAdapter {

    List<TemperatureData> data;

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(List<TemperatureData> myDataset) {
        data = myDataset;
    }
    @Override
    public Object getDataAtPosition(int position) {
        return data.get(position);
    }

    @Override
    public int getLayoutIdForType(int viewType) {
        return R.layout.rowlayout;
    }

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


回答1:


Not sure if you have already found a solution, but I managed to do it quite easily.

1) modify onCreateViewHolder method to look like this:

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // create a new view
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.rowlayout, parent, false);

    MainActivityPresenter presenter = new MainActivityPresenter(this, parent.getContext());
    binding.setVariable(BR.presenter,presenter);

    // set the view's size, margins, paddings and layout parameters
    return new MyViewHolder(binding);
}

2) make MyAdapter to implement MainActivityContract.View so in the end it looks like following:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements MainActivityContract.View

3) Implement necessary methods within MyAdapter; e.g:

@Override
public void showData(TemperatureData data) {
    String clickedItemCelsius = data.getCelsius();
}

4) Add Presenter variable to your row layout file:

    <variable
        name="presenter"
        type="com.mvvm.ViewModels.MainActivityPresenter"/>

5) Finally hook your onClick event under RelativeLayout:

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip"
    android:onClick="@{() -> presenter.onShowData(obj)}"
    >

Hope it helps!




回答2:


Probably the most common solution would be to put a click listener on the row layout's root view and call a method on your view model. For example in rowlayout.xml:

...
<RelativeLayout
    android:onClick="@{() -> obj.performClickAction()}"
....



回答3:


Hey I read that article about a week ago and had the same problem! The article barely mentions how actions should be handled but there is documentation on how to do it. In short, you are going to want a handler.

This handler is defined in your xml

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

example usage

<TextView android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@{user.firstName}"
       android:onClick="@{handlers::onClickFriend}"/>

The MyHandlers.java would look like this

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

You would change the add one more line to your MyAdapter.java

public class MyViewHolder extends RecyclerView.ViewHolder {
  public void bind(Object obj) {
                   binding.setVariable(BR.obj,obj);
                   binding.executePendingBindings();
                   binding.setHandlers(new MyHandlers());
            }

I haven't tested this code but if this doesn't work I can share my adapter .




回答4:


This way we can use the item click on databinding

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomView> {


    List<NewsModel> newsList;
    private LayoutInflater layoutInflater;


    public CustomAdapter(List<NewsModel> newsList)
    {
        this.newsList = newsList;
    }

    @Override
    public CustomView onCreateViewHolder(final ViewGroup parent, final int viewType) {


        if(layoutInflater == null)
        {
            layoutInflater = LayoutInflater.from(parent.getContext());
        }

        final NewsBinding newsBinding  = NewsBinding.inflate(layoutInflater,parent,false);

        newsBinding.setPresenter(new ClickListener() {
            @Override
            public void onclickListener() {

                Log.d("click me ","click me "+newsBinding.getNewsview().Title);
                Toast.makeText(parent.getContext(),""+newsBinding.getNewsview().Title,Toast.LENGTH_LONG).show();

            }
        });

      //  View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.innerlayout,parent,false);
       return new CustomView(newsBinding);
    }

    @Override
    public void onBindViewHolder(CustomView holder, int position) {

      //  News news = newsList.get(position);
       // holder.title.setText(news.getTitle());
       // holder.desc.setText(news.getDesc());

        NewsModel newsModel = newsList.get(position);
        holder.bind(newsModel);




    }

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

    public class CustomView extends RecyclerView.ViewHolder {

        private NewsBinding newsBinding;
       // TextView title, desc;
        public CustomView(NewsBinding newsBinding) {
            super(newsBinding.getRoot());

            this.newsBinding = newsBinding;
            //title = (TextView)itemView.findViewById(R.id.titleval);
            //desc =(TextView)itemView.findViewById(R.id.descval);

        }

        public void bind(NewsModel newsModel)
        {
            this.newsBinding.setNewsview(newsModel);
        }

        public NewsBinding getNewsBinding()
        {
            return newsBinding;
        }

    }
}

complete project is https://github.com/Vishulucky/DataBinding-MVVM.git




回答5:


our viewModel used in recycler view

class UserViewModel (val name: String?, val onClick: () -> Unit)

layout for user_item.xml

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

<data>
    <variable
        name="model"
        type="...model.UserViewModel" />
</data>

         <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="true"
                android:focusable="true"
                android:onClick="@{()->model.onClick.invoke()}"
                android:text="@{model.name}" />
<merge>

creating of models in presenter or modelView or somewhere else

fun loadData() {
   // ..
        val user = UserViewModel("name") { handleUserEvent() }

   .. //
 }

fun handleUserEvent() {
   // TODO handle on click
}



回答6:


If other suggestions don't seem to work the way you think it should, take a look at Google Codelab training, specifically "Interacting with RecyclerView items". It's a part of series, but if you are interested in handling the click event in RecyclerView (with Data Binding), you just need to read the aforementioned chapter only.

In short, 1) create a listener class with onClick(), 2) add listener class as data in list item's xml layout file, and 3) use android:onClick="{...}" to map the list item's click event to the listener.

I'm sure there are other ways to achieve the same goal, but this approach seems fairly straightforward.



来源:https://stackoverflow.com/questions/45723115/detecting-onclick-in-recycler-view-using-data-binding-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!