我正在探索RecyclerView,我很惊讶地看到,RecyclerView没有onItemClickListener()。
我有两个问题。
主要问题
我想知道为什么谷歌删除onItemClickListener()?
是否存在性能问题或其他问题?
次要的问题
我解决了我的问题写onClick在我的RecyclerView。适配器:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
这样可以吗/有更好的办法吗?
RecyclerView是如何不同于Listview?
一个区别是有一个LayoutManager类和RecyclerView,通过它你可以像-一样管理你的RecyclerView
水平或垂直滚动线性layoutmanager
GridLayout by GridLayoutManager
交错网格布局由StaggeredGridLayoutManager
就像水平滚动的RecyclerView-
LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);
Android Recyclerview与onItemClickListener,
为什么我们不能尝试这是工作像ListView。
来源:Link
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
@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 false;
}
@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
并设置这个为RecyclerView:
recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// TODO Handle item click
Log.e("@@@@@",""+position);
}
})
);
RecyclerView没有一个onItemClickListener,因为RecyclerView负责回收视图(惊讶!),所以回收视图的责任是处理它接收到的点击事件。
这实际上使它更容易使用,特别是如果你有可以在多个地方点击的项目。
无论如何,检测点击一个RecyclerView项目是非常容易的。你所需要做的就是定义一个接口(如果你不使用Kotlin,在这种情况下你只需要传入一个lambda):
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final Clicks clicks;
public MyAdapter(Clicks clicks) {
this.clicks = clicks;
}
private List<MyObject> items = Collections.emptyList();
public void updateData(List<MyObject> items) {
this.items = items;
notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
}
public interface Clicks {
void onItemSelected(MyObject myObject, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private MyObject myObject;
public MyViewHolder(View view) {
super(view);
// bind views
view.setOnClickListener((v) -> {
int adapterPosition = getBindingAdapterPosition();
if(adapterPosition >= 0) {
clicks.onItemSelected(myObject, adapterPosition);
}
});
}
public void bind(MyObject myObject) {
this.myObject = myObject;
// bind data to views
}
}
}
Kotlin中的代码相同:
class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
private var items: List<MyObject> = Collections.emptyList()
fun updateData(items: List<MyObject>) {
this.items = items
notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
}
inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
private lateinit var myObject: MyObject
init {
// binds views
myView.onClick {
val adapterPosition = getBindingAdapterPosition()
if(adapterPosition >= 0) {
itemClicks.invoke(myObject, adapterPosition)
}
}
}
fun bind(myObject: MyObject) {
this.myObject = myObject
// bind data to views
}
}
}
你不需要做的事情:
1)你不需要手动拦截触摸事件
2.)您不需要在子附加状态更改侦听器上添乱
3)你不需要RxJava中的PublishSubject/PublishRelay
只需使用点击侦听器。
如果你想添加onClick()到项目的子视图,例如,项目中的按钮,我发现你可以很容易地在你自己的RecyclerView的onCreateViewHolder()中做到这一点。适配器就像这样:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.cell, null);
Button btn = (Button) v.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do it
}
});
return new MyViewHolder(v);
}
我不知道这是不是一个好方法,但它很有效。如果有人有更好的想法,很高兴告诉我并纠正我的答案!:)
如果您有一个pojo列表,并且希望从适配器外部单击检索一个pojo,那么这里有一种非常容易实现它的方法。
在你的适配器中,为点击事件创建一个监听器和一个方法来设置它:
public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;
...
public interface OnItemClickListener {
public void onItemClick(MyPojo pojo);
}
...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}
...
}
在你的ViewHolder中,实现onClickListener并创建一个类成员来临时存储视图所呈现的POJO(这是一个例子,创建一个setter会更好):
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public MyPojo mCurrentPojo;
...
public ViewHolder(View view) {
super(v);
...
view.setOnClickListener(this); //You could set this on part of the layout too
}
...
@Override
public void onClick(View view) {
if(mOnItemClickListener != null && mCurrentPojo != null){
mOnItemClickListener.onItemClick(mCurrentPojo);
}
}
回到你的适配器,当ViewHolder被绑定时设置当前POJO(如果当前视图没有,则设置为null):
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final MyPojo currentPojo = mMyPojos.get(position);
holder.mCurrentPojo = currentPojo;
...
就是这样,现在你可以在你的fragment/activity中这样使用它:
mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
@Override
public void onItemClick(MyPojo pojo) {
//Do whatever you want with your pojo here
}
});