使用android中的数据绑定检测回收器视图中的onClick

时间:2017-08-16 21:15:34

标签: android android-recyclerview android-databinding

  1. 我在引用vogella-tutorial进行数据绑定
  2. 我想做什么:使用dataBinding检测每个项目的回收站视图行中的onClick的最佳方法是什么
  3. 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();
        }
    }
    

7 个答案:

答案 0 :(得分:4)

不确定您是否已找到解决方案,但我设法很容易做到了。

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内实施必要的方法; e.g:

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

4)将Presenter变量添加到行布局文件中:

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

5)最后将你的onClick事件挂在RelativeLayout:

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

希望它有所帮助!

答案 1 :(得分:0)

最常见的解决方案可能是在行布局的根视图上放置一个单击侦听器,并在视图模型上调用方法。 例如在rowlayout.xml中:

ourVersion = root.find('OurVersion')
ourVersion.set('default`, version)
currentVersion = ourVersion.find('CurrentVersion')
currentVersion.set('version', version)

答案 2 :(得分:0)

嘿,我在一周前阅读了那篇文章并遇到了同样的问题!该文章几乎没有提到应该如何处理行动,但documentation如何做到这一点。简而言之,您将需要<data> ... <variable name="handlers" type="com.example.MyHandlers"/> ... </data>

此处理程序在xml中定义

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

示例用法

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

MyHandlers.java看起来像这样

MyAdapter.java

您可以将另外一行添加到public class MyViewHolder extends RecyclerView.ViewHolder { public void bind(Object obj) { binding.setVariable(BR.obj,obj); binding.executePendingBindings(); binding.setHandlers(new MyHandlers()); }

Unable to start program filename.exe.  
Operation is not supported.  
Unknown error: 0x80070057.

我还没有对此代码进行测试,但如果这不起作用,我可以共享我的适配器。

答案 3 :(得分:0)

这样我们就可以使用项目点击数据绑定

        crtcInfo = d.xrandr_get_crtc_info(_data['crtc'],
            resources['config_timestamp'])
        x = crtcInfo.x
        y = crtcInfo.y

完整项目为https://github.com/Vishulucky/DataBinding-MVVM.git

答案 4 :(得分:0)

我们在回收站视图中使用的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>

在presenter或modelView或其他地方创建模型

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

   .. //
 }

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

答案 5 :(得分:0)

如果其他建议似乎没有按照您认为的方式起作用,请查看Google Codelab培训,特别是“ Interacting with RecyclerView items”。这是系列的一部分,但是如果您对处理RecyclerView(带有数据绑定)中的click事件感兴趣,则只需阅读上述章节即可。

简而言之,1)使用onClick()创建一个侦听器类,2)将侦听器类作为数据添加到列表项的xml布局文件中,以及3)使用android:onClick="{...}"将该列表项的click事件映射到听众。

我确定还有其他方法可以实现相同的目标,但是这种方法似乎很简单。

答案 6 :(得分:0)

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>

然后在您的活动中:

myAdapter.setOnItemClickListener { item->
         
           //your code here 
           
       }