有人使用RecyclerView找到了一种方法来设置一个onClickListener的项目在RecyclerView? 我想设置一个监听器为每个项目的布局,但这似乎有点太麻烦了 我确信有一种方法让RecyclerView监听onClick事件,但我不能完全弄清楚。


当前回答

我的方式

活动课上:

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

其他回答

由于API已经发生了根本性的变化,如果你要为每个项目创建一个OnClickListener,这不会让我感到惊讶。不过也没那么麻烦。在你的RecyclerView的实现中。适配器<MyViewHolder>,你应该有:

private final OnClickListener mOnClickListener = new MyOnClickListener();

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
    view.setOnClickListener(mOnClickListener);
    return new MyViewHolder(view);
}

onClick方法:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}

将类标记为抽象并实现OnClick方法

public abstract class MainGridAdapter extends
    RecyclerView.Adapter<MainGridAdapter.ViewHolder> {
private List<MainListItem> mDataset;

// 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 ViewHolder extends RecyclerView.ViewHolder {
    // each data item is just a string in this case
    public TextView txtHeader;
    public TextView txtFooter;

    public ViewHolder(View v) {
        super(v);
        txtHeader = (TextView) v.findViewById(R.id.firstLine);
        txtFooter = (TextView) v.findViewById(R.id.secondLine);
    }
}

public void add(int position, MainListItem item) {
    mDataset.add(position, item);
    notifyItemInserted(position);
}

public void remove(MainListItem item) {
    int position = mDataset.indexOf(item);
    mDataset.remove(position);
    notifyItemRemoved(position);
}

// Provide a suitable constructor (depends on the kind of dataset)
public MainGridAdapter(List<MainListItem> myDataset) {
    mDataset = myDataset;
}

// Create new views (invoked by the layout manager)
@Override
public MainGridAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {
    // create a new view
    View v = LayoutInflater.from(parent.getContext()).inflate(
            R.layout.list_item_grid_line, parent, false);
    // set the view's size, margins, paddings and layout parameters
    ViewHolder vh = new ViewHolder(v);
    return vh;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element     
    OnClickListener clickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            onItemClicked(position);
        }
    };
    holder.itemView.setOnClickListener(clickListener);
    holder.txtHeader.setOnClickListener(clickListener);
    holder.txtFooter.setOnClickListener(clickListener);
    final MainListItem item = mDataset.get(position);
    holder.txtHeader.setText(item.getTitle());
    if (TextUtils.isEmpty(item.getDescription())) {
        holder.txtFooter.setVisibility(View.GONE);
    } else {
        holder.txtFooter.setVisibility(View.VISIBLE);
        holder.txtFooter.setText(item.getDescription());
    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    return mDataset.size();
}

public abstract void onItemClicked(int position);

}

在绑定事件中实现单击处理程序,使其只有一个事件实现

执行此:

mAdapter = new MainGridAdapter(listItems) {         
    @Override
    public void onItemClicked(int position) {
        showToast("Item Clicked: " + position, ToastPlus.STYLE_INFO);
    }
};

同样可以做长时间点击

在kotlin中使用构造函数实现

初始化你的RecyclerView构造函数,如下所示:

class ListAdapter(
    c: Context,
    private var list: List<Project>,
    private val itemClick: (Project) -> Unit
) : RecyclerView.Adapter<ListAdapter.ViewHolder>() 

在onCreateViewHolder中使用itemClick返回:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):ProjectViewHolder {
    val view = inflater.inflate(R.layout.list_item, parent, false)
    return ViewHolder(view, itemClick)
}

你的onBindViewHolder:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bindProject(list[position])
}

然后用ViewHolder类创建bindProject函数。

class ViewHolder(
    view: View,
    private val itemClick: (Project) -> Unit
) : RecyclerView.ViewHolder(view) {

    private val clientTextCount = 7

    val titleTextView: TextView = view.projectTitleTextView
 
    fun bindProject(project: Project) {
        with(project) {
            titleTextView.text = name
            itemView.setOnClickListener { itemClick(this) }
        }
    }
}

最后在您的活动中用lazy初始化适配器

private val adapter: ListAdapter by lazy {
    ListAdapter(this, projectList, {
        // Here you can implement your onClick function.
    })
}

在适配器中为RecyclerView添加新列表初始化以下方法:

fun setProjects(projects: List<Project>) {
    projectList = projects
    notifyDataSetChanged()
}

在你的活动中调用setProjects方法:

adapter.setProjects(projects)

就是这样。

这里有一个策略,它给出了一个类似于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;
    }
};

有更简单的方法。只需要在根视图上应用onBindViewHolder中的click。

考虑这是你对适配器的看法,

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1dp"
            android:textSize="15sp" />
</LinearLayout>

然后在适配器中执行以下操作

//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
    ViewHolder1 viewHolder = new ViewHolder1(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {

    //apply on click on your root view
    holder.linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Do on click stuff
        }
    });
}

//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

    public CareerLinksViewHolder(View itemView) {
        super(itemView);

        this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
        this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
    }
}