使用 android 中的数据绑定检测回收器视图中的 onClick
Detecting onClick in recycler view using data binding in android
- 我正在参考 vogella-tutorial 进行数据绑定
- 我正在尝试做什么:使用 dataBinding
在回收站视图行中检测每个项目的 onClick 的最佳方法是什么
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();
}
}
可能最常见的解决方案是在行布局的根视图上放置一个点击侦听器,然后在您的视图模型上调用一个方法。
例如 rowlayout.xml:
...
<RelativeLayout
android:onClick="@{() -> obj.performClickAction()}"
....
嘿,我大约一周前读了那篇文章,遇到了同样的问题!这篇文章几乎没有提到应该如何处理操作,但有 documentation 如何处理。简而言之,您将需要 handler
.
此处理程序在您的 xml
中定义
<data>
...
<variable name="handlers" type="com.example.MyHandlers"/>
...
</data>
用法示例
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/>
MyHandlers.java 看起来像这样
public class MyHandlers {
public void onClickFriend(View view) { ... }
}
您可以更改添加一行到您的 MyAdapter.java
public class MyViewHolder extends RecyclerView.ViewHolder {
public void bind(Object obj) {
binding.setVariable(BR.obj,obj);
binding.executePendingBindings();
binding.setHandlers(new MyHandlers());
}
我还没有测试过这段代码,但如果这不起作用,我可以分享我的适配器。
不确定您是否已经找到解决方案,但我很容易做到。
1) 修改 onCreateViewHolder
方法如下:
@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) 让 MyAdapter 实现 MainActivityContract.View
所以最后它看起来像下面这样:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements MainActivityContract.View
3) 在MyAdapter
内实现必要的方法;例如:
@Override
public void showData(TemperatureData data) {
String clickedItemCelsius = data.getCelsius();
}
4) 将 Presenter 变量添加到您的行布局文件:
<variable
name="presenter"
type="com.mvvm.ViewModels.MainActivityPresenter"/>
5) 最后在 RelativeLayout 下挂钩您的 onClick
事件:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:onClick="@{() -> presenter.onShowData(obj)}"
>
希望对您有所帮助!
这样我们就可以使用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;
}
}
}
我们在回收站视图中使用的 viewModel
class UserViewModel (val name: String?, val onClick: () -> Unit)
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>
在演示者或模型视图或其他地方创建模型
fun loadData() {
// ..
val user = UserViewModel("name") { handleUserEvent() }
.. //
}
fun handleUserEvent() {
// TODO handle on click
}
如果其他建议似乎没有按照您认为的方式发挥作用,请查看 Google Codelab 培训,特别是“Interacting with RecyclerView items”。这是系列的一部分,但如果你对处理 RecyclerView 中的点击事件(使用数据绑定)感兴趣,你只需要阅读上述章节即可。
简而言之,1) 使用 onClick()
创建监听器 class,2) 在列表项的 xml 布局文件中添加监听器 class 作为数据,以及 3)使用 android:onClick="{...}"
将列表项的点击事件映射到侦听器。
我敢肯定还有其他方法可以实现相同的目标,但这种方法似乎相当简单。
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 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>
然后在你的 activity 中:
myAdapter.setOnItemClickListener { item->
//your code here
}
- 我正在参考 vogella-tutorial 进行数据绑定
- 我正在尝试做什么:使用 dataBinding 在回收站视图行中检测每个项目的 onClick 的最佳方法是什么
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();
}
}
可能最常见的解决方案是在行布局的根视图上放置一个点击侦听器,然后在您的视图模型上调用一个方法。 例如 rowlayout.xml:
...
<RelativeLayout
android:onClick="@{() -> obj.performClickAction()}"
....
嘿,我大约一周前读了那篇文章,遇到了同样的问题!这篇文章几乎没有提到应该如何处理操作,但有 documentation 如何处理。简而言之,您将需要 handler
.
此处理程序在您的 xml
中定义<data>
...
<variable name="handlers" type="com.example.MyHandlers"/>
...
</data>
用法示例
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{handlers::onClickFriend}"/>
MyHandlers.java 看起来像这样
public class MyHandlers {
public void onClickFriend(View view) { ... }
}
您可以更改添加一行到您的 MyAdapter.java
public class MyViewHolder extends RecyclerView.ViewHolder {
public void bind(Object obj) {
binding.setVariable(BR.obj,obj);
binding.executePendingBindings();
binding.setHandlers(new MyHandlers());
}
我还没有测试过这段代码,但如果这不起作用,我可以分享我的适配器。
不确定您是否已经找到解决方案,但我很容易做到。
1) 修改 onCreateViewHolder
方法如下:
@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) 让 MyAdapter 实现 MainActivityContract.View
所以最后它看起来像下面这样:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements MainActivityContract.View
3) 在MyAdapter
内实现必要的方法;例如:
@Override
public void showData(TemperatureData data) {
String clickedItemCelsius = data.getCelsius();
}
4) 将 Presenter 变量添加到您的行布局文件:
<variable
name="presenter"
type="com.mvvm.ViewModels.MainActivityPresenter"/>
5) 最后在 RelativeLayout 下挂钩您的 onClick
事件:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:onClick="@{() -> presenter.onShowData(obj)}"
>
希望对您有所帮助!
这样我们就可以使用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;
}
}
}
我们在回收站视图中使用的 viewModel
class UserViewModel (val name: String?, val onClick: () -> Unit)
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>
在演示者或模型视图或其他地方创建模型
fun loadData() {
// ..
val user = UserViewModel("name") { handleUserEvent() }
.. //
}
fun handleUserEvent() {
// TODO handle on click
}
如果其他建议似乎没有按照您认为的方式发挥作用,请查看 Google Codelab 培训,特别是“Interacting with RecyclerView items”。这是系列的一部分,但如果你对处理 RecyclerView 中的点击事件(使用数据绑定)感兴趣,你只需要阅读上述章节即可。
简而言之,1) 使用 onClick()
创建监听器 class,2) 在列表项的 xml 布局文件中添加监听器 class 作为数据,以及 3)使用 android:onClick="{...}"
将列表项的点击事件映射到侦听器。
我敢肯定还有其他方法可以实现相同的目标,但这种方法似乎相当简单。
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 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>
然后在你的 activity 中:
myAdapter.setOnItemClickListener { item->
//your code here
}