有人使用RecyclerView找到了一种方法来设置一个onClickListener的项目在RecyclerView? 我想设置一个监听器为每个项目的布局,但这似乎有点太麻烦了 我确信有一种方法让RecyclerView监听onClick事件,但我不能完全弄清楚。
当前回答
这里有一个策略,它给出了一个类似于ListView实现的结果,因为你可以在活动或片段级别而不是适配器或ViewHolder级别定义侦听器。它还定义了一些抽象类,这些抽象类负责适配器和持有者的大量样板工作。
抽象类
首先,定义一个抽象Holder,它扩展了RecyclerView。并定义了一个泛型数据类型T,用于将数据绑定到视图。bindViews方法将由一个子类实现,用于将数据映射到视图。
public abstract class Holder<T> extends RecyclerView.ViewHolder {
T data;
public Holder(View itemView) {
super(itemView);
}
public void bindData(T data){
this.data = data;
bindViews(data);
}
abstract protected void bindViews(T data);
}
同样,创建一个抽象适配器,扩展RecyclerView.Adapter<Holder<T>>。这定义了3个接口方法中的2个,子类将需要实现最后一个onViewHolderCreated方法。
public abstract class Adapter<T> extends RecyclerView.Adapter<Holder<T>> {
List<T> list = new ArrayList<>();
@Override
public void onBindViewHolder(Holder<T> holder, int position) {
holder.bindData(list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
public T getItem(int adapterPosition){
return list.get(adapterPosition);
}
}
具体类
现在创建一个扩展Holder的新具体类。该方法只需定义视图并处理绑定。这里我使用ButterKnife库,但请随意使用itemView.findViewById(…)方法代替。
public class PersonHolder extends Holder<Person>{
@Bind(R.id.firstname) TextView firstname;
@Bind(R.id.lastname) TextView lastname;
public PersonHolder(View view){
super(view);
ButterKnife.bind(this, view);
}
@Override
protected void bindViews(Person person) {
firstname.setText(person.firstname);
lastname.setText(person.lastname);
}
}
最后,在持有RecyclerView的Activity或Fragment类中,你会有这样的代码:
// Create adapter, this happens in parent Activity or Fragment of RecyclerView
adapter = new Adapter<Person>(){
@Override
public PersonHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_person_view, parent, false);
PersonHolder holder = new PersonHolder(v);
v.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
int itemPos = holder.getAdapterPosition();
Person person = getItem(itemPos);
// do something with person
EventBus.getDefault().postSticky(new PersonClickedEvent(itemPos, person));
}
});
return holder;
}
};
其他回答
我的方式
活动课上:
public class MyActivity extends AppCompatActivity implements EmployeeAdapter.ClickListener {
...
@Override
public void onClick(int position) { ... }
...
}
适配器类:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
@Override
public void onBindViewHolder(){
holder.textView1.setOnClickListener(v -> clickListener.onClick(position));
}
...
public interface ClickListener {
void onClick(int position);
}
...
}
别白费力气了!这个特定用例的代码包含在Android Studio附带的Master/Detail Flow启动器项目中。
从Android Studio选择:
文件>新建>新建项目.... 在Phone and Tablet选项卡中选择如下所示的Master/Detail Flow。
用Kotlin或Java创建项目。 利润。
我不会在这里包括谷歌的ootb演示项目的代码,但我会概述谷歌提供的示例中的主要设计方法:
the item OnClickListener is created ONLY ONCE, and is assigned to a field in your RecyclerView.Adapter implementation. in the onBindViewHolder() you should set the same, pre-created onClickListener object on your ViewHolder instance with holder.itemView.setOnClickListener(mOnClickListener) (AVOID creating a new instance on every method call!); if you need to capture clicks on some specific elements inside the ViewHolder then extend ViewHolder and expose the elements you need as fields so that you can attach whatever listeners you need in onBindViewHolder() — and once again, do NOT re-create the listeners on every method call — initialise them as instance fields and attach them as needed. you can use .setTag() in order to pass state to your viewHolder, e.g. holder.itemView.setTag(mValues.get(position)); as used in the demo.
我有一个很好的解决方案RecyclerView的onItemClickListener的项目和子项
步骤1—创建接口
public interface OnRecyclerViewItemClickListener
{
/**
* Called when any item with in recyclerview or any item with in item
* clicked
*
* @param position
* The position of the item
* @param id
* The id of the view which is clicked with in the item or
* -1 if the item itself clicked
*/
public void onRecyclerViewItemClicked(int position, int id);
}
步骤2-然后在适配器的onBindViewHolder方法中使用它,如下所示
/**
* Custom created method for Setting the item click listener for the items and items with in items
* @param listener OnRecyclerViewItemClickListener
*/
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
{
this.listener = listener;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position)
{
// viewHolder.albumBg.setBackgroundResource(_itemData[position]
// .getImageUrl());
viewHolder.albumName.setText(arrayList.get(position).getName());
viewHolder.artistName.setText(arrayList.get(position).getArtistName());
String imgUrl = arrayList.get(position).getThumbImageUrl();
makeImageRequest(imgUrl, viewHolder);
viewHolder.parentView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, -1);
}
});
viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, v.getId());
}
});
}
// class to hold a reference to each item of RecyclerView
public static class ViewHolder extends RecyclerView.ViewHolder
{
public TextView albumName, artistName;
public ImageView albumIcon, settingButton;
public LinearLayout parentView;
public ViewHolder(View itemLayoutView)
{
super(itemLayoutView);
// albumBg = (LinearLayout) itemLayoutView
// .findViewById(R.id.albumDlbg);
albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
artistName = (TextView) itemLayoutView
.findViewById(R.id.artistName);
albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
parentView = (LinearLayout) itemLayoutView
.findViewById(R.id.albumDlbg);
settingButton = (ImageView) itemLayoutView
.findViewById(R.id.settingBtn);
}
}
步骤3-在活动或片段中找到并设置回收器视图,您正在使用此
recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);
lm = new LinearLayoutManager(mActivity);
lm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(lm);
recyclerView.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(getActivity())
.paint(Utils.getPaint()).build());
PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
mActivity, true);
// set adapter
recyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(this);
// set item animator to DefaultAnimator
recyclerView.setItemAnimator(new DefaultItemAnimator());
步骤4-最后在使用recyclerview的activity或fragment中实现接口
@Override
public void onRecyclerViewItemClicked(int position, int id)
{
if(id==-1){
Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
}
}
更新Kotlin语言 我已经更新了kotlin的代码,其中只有整个视图有点击监听器。你可以根据上面的java代码编辑界面和代码来设置子项点击监听器。
适配器
class RecentPostsAdapter(private val list: MutableList<Post>) :
RecyclerView.Adapter<RecentPostsAdapter.ViewHolder>() {
private lateinit var onItemClickListener: OnItemClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.listitem_recent_post, parent, false)
)
}
override fun getItemCount(): Int {
return list.size
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.onItemClickListener = onItemClickListener
}
private fun getItem(position: Int): Post {
return list[position]
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
holder.itemView.setOnClickListener(View.OnClickListener {
onItemClickListener.onItemClick(
position
)
})
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private var imageView: NetworkImageView? = null
private var tvTitle: TextView? = null
private var tvExcerpt: TextView? = null
private var htmlSpanner: HtmlSpanner = HtmlSpanner()
init {
imageView = itemView.findViewById(R.id.niv_post_image)
tvTitle = itemView.findViewById(R.id.tv_post_title)
tvExcerpt = itemView.findViewById(R.id.tv_post_excerpt)
}
fun bind(post: Post) {
tvTitle?.text = post.title
tvExcerpt?.text = htmlSpanner.fromHtml(post.excerpt)
}
}
interface OnItemClickListener {
fun onItemClick(position: Int)
}
}
活动或片段
recyclerView = view.findViewById(R.id.rvHomeRecentPosts)
recyclerView.layoutManager = LinearLayoutManager(view.context)
list = mutableListOf()
recentPostsAdapter = RecentPostsAdapter(list)
recyclerView.adapter = recentPostsAdapter
recentPostsAdapter.setOnItemClickListener(object:RecentPostsAdapter.OnItemClickListener{
override fun onItemClick(position: Int) {
(activity as MainActivity).findNavController(R.id.nav_host_fragment).navigate(R.id.action_nav_home_to_nav_post_detail)
}
})
让我们看看如何在Jetpack / AndroidX中实现这一点
你需要像这样在viewmodel类中创建一个观察对象
private MutableLiveData<Integer> adapterItem = new MutableLiveData<>();
public MutableLiveData<Integer> getAdapterItem() {
return adapterItem;
}
public void setAdapterItem(int adapterItem) {
this.getAdapterItem().setValue(adapterItem);
}
然后在适配器类中,确保将viewmodel引用作为构造函数的参数传递,然后在vieholder上实现clicklistener
public MyViewHolder(@NonNull View itemView) {
super(itemView);
if(itemView != null){
itemView.setOnClickListener(v -> {
int adapterPosition = getAdapterPosition();
viewModel.setAdapterItem(adapterPosition);
});
};
}
然后从活动课上观察变化
viewModel.getAdapterItem().observe(this, position -> {
Log.w(TAG, "clicked: " + ridesArray.get(position));
});
这里有一个更好的和不那么紧密耦合的方式来实现一个OnClickListener的RecyclerView。
用法片段:
RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) {
// do whatever
}
@Override public void onLongItemClick(View view, int position) {
// do whatever
}
})
);
RecyclerItemClickListener实现:
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
public void onLongItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
@Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
return true;
}
return false;
}
@Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }
@Override
public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 碎片中的onCreateOptionsMenu
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?