Reputation: 42824
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();
}
}
Upvotes: 16
Views: 28018
Reputation: 2796
class MyAdapter() :
RecyclerView.Adapter<MyAdapter.MyViewHolder> {
inner class MyViewHolder(private val binding: ItemMyListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(yourItem: YourItem) {
binding.setVariable(BR.item, yourItem)
binding.executePendingBindings()
binding.animeListCard.setOnClickListener {
onItemClickListener?.let { click ->
click(yourItem)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ItemMyListBinding = DataBindingUtil.inflate(
layoutInflater,
R.layout.item_My_list,
parent,
false
)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(getItem(position))
}
//add these
private var onItemClickListener: (( YourItem) -> Unit)? = null
fun setOnItemClickListener(listener: ( YourItem) -> Unit) {
onItemClickListener = listener
}
}
R.layout.item_My_list layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.temp.example.data.MyItem" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{item.title}"
/>
</LinearLayout>
</layout>
then in your activity :
myAdapter.setOnItemClickListener { item->
//your code here
}
Upvotes: 0
Reputation: 3214
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.
Upvotes: 1
Reputation: 51
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
}
Upvotes: 2
Reputation: 478
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
Upvotes: 0
Reputation: 2701
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!
Upvotes: 9
Reputation: 187
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 .
Upvotes: 1
Reputation: 109
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()}"
....
Upvotes: 1