web-dev-qa-db-fra.com

Détecter onClick dans la vue Recycler à l'aide de la liaison de données dans Android

  1. Je me réfère à vogella-tutorial pour la liaison de données
  2. Ce que j'essaie de faire: Quel est le meilleur moyen de détecter onClick dans la ligne de la vue Recycler pour chaque élément à l'aide de la liaison de données

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();
    }
}

5
Devrath

Je ne sais pas si vous avez déjà trouvé une solution, mais j'ai réussi à le faire assez facilement.

1) modifiez la méthode onCreateViewHolder pour ressembler à ceci:

@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) oblige MyAdapter à implémenter MainActivityContract.View pour qu’il se présente comme suit: 

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

3) implémenter les méthodes nécessaires dans MyAdapter; par exemple:

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

4) Ajoutez la variable Presenter à votre fichier d’agencement de lignes:

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

5) Enfin, décrochez votre événement onClick sous RelativeLayout:

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

J'espère que ça aide! 

3
Robert J.

Hey j'ai lu cet article il y a environ une semaine et j'ai eu le même problème! L'article mentionne à peine comment les actions doivent être traitées, mais il existe une documentation sur la façon de le faire. En bref, vous allez vouloir une handler.

Ce gestionnaire est défini dans votre xml 

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

exemple d'utilisation 

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

Le MyHandlers.Java ressemblerait à ceci

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

Vous voudriez changer l’ajout d’une ligne à votre MyAdapter.Java

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

Je n'ai pas testé ce code mais si cela ne fonctionne pas, je peux partager mon adaptateur.

0
Seabass77

De cette façon, nous pouvons utiliser l'élément click sur 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;
        }

    }
}

projet complet est https://github.com/Vishulucky/DataBinding-MVVM.git

0
Vishal

La solution la plus courante consiste probablement à placer un écouteur de clic sur la vue racine de la présentation de ligne et à appeler une méthode sur votre modèle de vue .

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

notre vueModèle utilisé dans la vue recycleur

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

layout pour 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>

création de modèles dans présentateur ou modelView ou ailleurs

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

   .. //
 }

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