tl;dr 2016 Use RxJava and a PublishSubject to expose an Observable for the clicks.
(tl 2016年博士使用RxJava和PublishSubject公开点击的可观察对象。)
public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data", "In", "Adapter" };
private final PublishSubject<String> onClickSubject = PublishSubject.create();
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String element = mDataset[position];
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickSubject.onNext(element);
}
});
}
public Observable<String> getPositionClicks(){
return onClickSubject.asObservable();
}
}
Original Post:
(原始帖子:)
Since the introduction of ListView
, onItemClickListener
has been problematic.
(自从引入ListView
以来, onItemClickListener
一直存在问题。)
The moment you have a click listener for any of the internal elements the callback would not be triggered but it wasn't notified or well documented (if at all) so there was a lot of confusion and SO questions about it. (当您拥有用于任何内部元素的单击侦听器时,将不会触发该回调,但是该回调没有得到通知或没有得到充分的文档记录(如果有的话)(因此),因此存在很多混乱和疑问。)
Given that RecyclerView
takes it a step further and doesn't have a concept of a row/column, but rather an arbitrarily laid out amount of children, they have delegated the onClick to each one of them, or to programmer implementation.
(鉴于RecyclerView
更进一步,它没有行/列的概念,而是任意布局的子代,因此他们将onClick委托给了每个子代或程序员实现。)
Think of Recyclerview
not as a ListView
1:1 replacement but rather as a more flexible component for complex use cases.
(不要将Recyclerview
视为ListView
1:1的替代品,而Recyclerview
视为用于复杂用例的更灵活的组件。)
And as you say, your solution is what google expected of you. (正如您所说,您的解决方案就是Google对您的期望。)
Now you have an adapter who can delegate onClick to an interface passed on the constructor, which is the correct pattern for both ListView
and Recyclerview
. (现在,您有了一个适配器,可以将onClick委托给在构造函数上传递的接口,这是ListView
和Recyclerview
的正确模式。)
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public IMyViewHolderClicks mListener;
public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
super(itemLayoutView);
mListener = listener;
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
imgViewIcon.setOnClickListener(this);
itemLayoutView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v instanceof ImageView){
mListener.onTomato((ImageView)v);
} else {
mListener.onPotato(v);
}
}
public static interface IMyViewHolderClicks {
public void onPotato(View caller);
public void onTomato(ImageView callerImage);
}
}
and then on your adapter
(然后在您的适配器上)
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data" };
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() {
public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
});
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Get element from your dataset at this position
// Replace the contents of the view with that element
// Clear the ones that won't be used
holder.txtViewTitle.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
...
Now look into that last piece of code: onCreateViewHolder(ViewGroup parent, int viewType)
the signature already suggest different view types.
(现在查看最后一段代码: onCreateViewHolder(ViewGroup parent, int viewType)
签名已经建议了不同的视图类型。)
For each one of them you'll require a different viewholder too, and subsequently each one of them can have a different set of clicks. (对于其中的每一个,您也将需要一个不同的视图持有者,随后,每个人都可以具有不同的点击集。)
Or you can just create a generic viewholder that takes any view and one onClickListener
and applies accordingly. (或者,您可以只创建一个通用的视图持有者,该视图持有者使用任何视图和一个onClickListener
并相应地应用。)
Or delegate up one level to the orchestrator so several fragments/activities have the same list with different click behaviour. (或将一个级别委派给协调器,以便多个片段/活动具有相同的列表且具有不同的单击行为。)
Again, all flexibility is on your side. (同样,所有灵活性都在您身边。)
It is a really needed component and fairly close to what our internal implementations and improvements to ListView
were until now.
(它是一个真正需要的组件,与我们迄今为止对ListView
内部实现和改进非常接近。)
It's good that Google finally acknowledges it. (Google最终承认这一点是一件好事。)