在 Adapter/ViewHolder 中处理点击事件
Handle click events in Adapter/ViewHolder
目前:
我正在 onBindViewHolder
内的 Adapter
中实现点击事件,但我注意到在执行此操作时适配器位置会变得混乱。我做了一些研究,发现 ,他说:
As for why it is better in the ViewHolder instead of in onBindViewHolder(), that is because onBindViewHolder() is called for each and every item and setting the click listener is an unnecessary option to repeat when you can call it once in your ViewHolder constructor.
他引用的示例如下所示:
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnItemClickListener {
public MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
}
@Override
public void OnClick(View view) {
// Get the item clicked
// For this example, I'm assuming your data source is of type `List<MyObject>`
MyObject myObject = mDataSource.get(getAdapterPosition());
// Then you can do any actions on it, for example -
myObject.setChecked();
}
}
这对我来说很有意义,但我的问题是我的 ViewHolder
中有一个 ImageButton
,他的示例仅展示了如何处理 ViewHolder
本身的点击事件.请先看看我的适配器目前的样子:
public class MyAdapter extends Adapter<MyAdapter.ViewHolder> {
ArrayList<Bitmap> bitmapArrayList;
Context context;
LayoutInflater layoutInflater;
View myLayoutView;
ArrayList<PathModel> swingThumbPathList;
ArrayList<PathModel> swingVideoPathList = new ArrayList();
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.myLayoutView = LayoutInflater.from(this.context).inflate(R.layout.single_item, parent, false);
return new ViewHolder(this.myLayoutView);
}
public void onBindViewHolder(ViewHolder myHolder, final int position) {
final ViewHolder holder = myHolder;
holder.viewholderOtions = (ImageButton) myLayoutView.findViewById(R.id.viewholderOptions);
holder.name = (TextView) this.myLayoutView.findViewById(R.id.name);
holder.image = (CircularImageView) this.myLayoutView.findViewById(R.id.image);
holder.name.setText(Model.getPath());
holder.image.setImageURI(Uri.parse(Model.getPath()));
holder.viewholderOtions.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(holder.itemView.getContext(), "Options was clicked", Toast.LENGTH_LONG).show();
showPopupMenu(holder.viewholderOtions, position);
}
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String uri = holder.name.getText().toString();
Toast.makeText(holder.itemView.getContext(), uri, Toast.LENGTH_LONG).show();
}
});
}
private void showPopupMenu(final View view, final int position) {
// inflate menu
PopupMenu popup = new PopupMenu(view.getContext(), view);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.popup_menu, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
//The correct position is being toasted
Toast.makeText(view.getContext(), position + "Delete", Toast.LENGTH_LONG).show();
return true;
case R.id.rename:
Toast.makeText(view.getContext(), "Rename", Toast.LENGTH_LONG).show();
return true;
default:
return true;
}
}
});
popup.show();
}
我的问题
如何处理 ViewHolder
本身和 ViewHolder
内部的 ImageButton
的点击事件?
在你的 ViewHolder 构造函数中做这样的事情
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
// initialize your view here and set click listener
name = (TextView) itemView.findViewById(R.id.name);
name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// do your stuffs
}
});
}
public void setText(String text){
// do your thing
}
}
现在在你的 onBindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setText("The text you want to pass to view holder");
}
而且我不认为使用全局 myLayoutView
是个好主意。它会扰乱你的观点。而是使用 viewHolder.itemview
回头看这个问题我笑了,所以在将近 2 年后回答我自己的问题。
使用问题中提供的相同逻辑,这就是您将点击事件设置为视图本身的方式,以及视图内的元素,在 viewholder 内而不是 onBindViewHolder
public class MyAdapter extends Adapter<MyAdapter.ViewHolder> {
ArrayList<Bitmap> bitmapArrayList;
Context context;
LayoutInflater layoutInflater;
View myLayoutView;
ArrayList<PathModel> swingThumbPathList;
ArrayList<PathModel> swingVideoPathList = new ArrayList();
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
viewholderOtions = itemView.findViewById(R.id.viewholderOptions);
videoName = itemView.findViewById(R.id.FilePath);
videoThumb = itemView.findViewById(R.id.VideoThumbnail);
//set OnClickListener's for the views we want click events for
itemView.setOnClickListener(this);
viewholderOtions.setOnClickListener(this);
videoThumb.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//get the tag that we have set in onBindViewHolder
int position = (int) v.getTag();
if (v == viewholderOtions) {
//viewholderOtions was selected, we can use the position above to see what item, as shown below:
Log.e("viewholderOtions at position =", String.valueOf(position);
}
if (v == itemView){
//itemView was selected, we can use the position above to see what item, as shown below:
Log.e("itemView at position =", String.valueOf(position);
}
if (v == videoThumbvideoThumb){
//itemView was selected, we can use the position above to see what item, as shown below:
Log.e("videoThumbvideoThumb at position =", String.valueOf(position);
}
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.myLayoutView = LayoutInflater.from(this.context).inflate(R.layout.single_item, parent, false);
return new ViewHolder(this.myLayoutView);
}
public void onBindViewHolder(ViewHolder myHolder, final int position) {
//set a tag so we can retrieve the position via the tag
myHolder.viewholderOtions.setTag(position);
//Set text to holder.name
holder.name.setText(Model.getPath());
//a better option to below is to use a library like picasso to handle the image loading
holder.image.setImageURI(Uri.parse(Model.getPath()));
}
}
不过老实说,我还是在onBindViewHolder
里面设置了点击事件,然后我就在我的Activity
-recyclerView.setHasFixedSize(true);
里面设置了下面的RecyclerView
。正如我的问题中所述,通过这样做,位置不会搞砸。
目前:
我正在 onBindViewHolder
内的 Adapter
中实现点击事件,但我注意到在执行此操作时适配器位置会变得混乱。我做了一些研究,发现
As for why it is better in the ViewHolder instead of in onBindViewHolder(), that is because onBindViewHolder() is called for each and every item and setting the click listener is an unnecessary option to repeat when you can call it once in your ViewHolder constructor.
他引用的示例如下所示:
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnItemClickListener {
public MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
}
@Override
public void OnClick(View view) {
// Get the item clicked
// For this example, I'm assuming your data source is of type `List<MyObject>`
MyObject myObject = mDataSource.get(getAdapterPosition());
// Then you can do any actions on it, for example -
myObject.setChecked();
}
}
这对我来说很有意义,但我的问题是我的 ViewHolder
中有一个 ImageButton
,他的示例仅展示了如何处理 ViewHolder
本身的点击事件.请先看看我的适配器目前的样子:
public class MyAdapter extends Adapter<MyAdapter.ViewHolder> {
ArrayList<Bitmap> bitmapArrayList;
Context context;
LayoutInflater layoutInflater;
View myLayoutView;
ArrayList<PathModel> swingThumbPathList;
ArrayList<PathModel> swingVideoPathList = new ArrayList();
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.myLayoutView = LayoutInflater.from(this.context).inflate(R.layout.single_item, parent, false);
return new ViewHolder(this.myLayoutView);
}
public void onBindViewHolder(ViewHolder myHolder, final int position) {
final ViewHolder holder = myHolder;
holder.viewholderOtions = (ImageButton) myLayoutView.findViewById(R.id.viewholderOptions);
holder.name = (TextView) this.myLayoutView.findViewById(R.id.name);
holder.image = (CircularImageView) this.myLayoutView.findViewById(R.id.image);
holder.name.setText(Model.getPath());
holder.image.setImageURI(Uri.parse(Model.getPath()));
holder.viewholderOtions.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(holder.itemView.getContext(), "Options was clicked", Toast.LENGTH_LONG).show();
showPopupMenu(holder.viewholderOtions, position);
}
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String uri = holder.name.getText().toString();
Toast.makeText(holder.itemView.getContext(), uri, Toast.LENGTH_LONG).show();
}
});
}
private void showPopupMenu(final View view, final int position) {
// inflate menu
PopupMenu popup = new PopupMenu(view.getContext(), view);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.popup_menu, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
//The correct position is being toasted
Toast.makeText(view.getContext(), position + "Delete", Toast.LENGTH_LONG).show();
return true;
case R.id.rename:
Toast.makeText(view.getContext(), "Rename", Toast.LENGTH_LONG).show();
return true;
default:
return true;
}
}
});
popup.show();
}
我的问题
如何处理 ViewHolder
本身和 ViewHolder
内部的 ImageButton
的点击事件?
在你的 ViewHolder 构造函数中做这样的事情
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
// initialize your view here and set click listener
name = (TextView) itemView.findViewById(R.id.name);
name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// do your stuffs
}
});
}
public void setText(String text){
// do your thing
}
}
现在在你的 onBindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setText("The text you want to pass to view holder");
}
而且我不认为使用全局 myLayoutView
是个好主意。它会扰乱你的观点。而是使用 viewHolder.itemview
回头看这个问题我笑了,所以在将近 2 年后回答我自己的问题。
使用问题中提供的相同逻辑,这就是您将点击事件设置为视图本身的方式,以及视图内的元素,在 viewholder 内而不是 onBindViewHolder
public class MyAdapter extends Adapter<MyAdapter.ViewHolder> {
ArrayList<Bitmap> bitmapArrayList;
Context context;
LayoutInflater layoutInflater;
View myLayoutView;
ArrayList<PathModel> swingThumbPathList;
ArrayList<PathModel> swingVideoPathList = new ArrayList();
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
TextView name;
CircularImageView image;
ImageButton viewholderOtions;
ViewHolder(View itemView) {
super(itemView);
viewholderOtions = itemView.findViewById(R.id.viewholderOptions);
videoName = itemView.findViewById(R.id.FilePath);
videoThumb = itemView.findViewById(R.id.VideoThumbnail);
//set OnClickListener's for the views we want click events for
itemView.setOnClickListener(this);
viewholderOtions.setOnClickListener(this);
videoThumb.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//get the tag that we have set in onBindViewHolder
int position = (int) v.getTag();
if (v == viewholderOtions) {
//viewholderOtions was selected, we can use the position above to see what item, as shown below:
Log.e("viewholderOtions at position =", String.valueOf(position);
}
if (v == itemView){
//itemView was selected, we can use the position above to see what item, as shown below:
Log.e("itemView at position =", String.valueOf(position);
}
if (v == videoThumbvideoThumb){
//itemView was selected, we can use the position above to see what item, as shown below:
Log.e("videoThumbvideoThumb at position =", String.valueOf(position);
}
}
}
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
this.myLayoutView = LayoutInflater.from(this.context).inflate(R.layout.single_item, parent, false);
return new ViewHolder(this.myLayoutView);
}
public void onBindViewHolder(ViewHolder myHolder, final int position) {
//set a tag so we can retrieve the position via the tag
myHolder.viewholderOtions.setTag(position);
//Set text to holder.name
holder.name.setText(Model.getPath());
//a better option to below is to use a library like picasso to handle the image loading
holder.image.setImageURI(Uri.parse(Model.getPath()));
}
}
不过老实说,我还是在onBindViewHolder
里面设置了点击事件,然后我就在我的Activity
-recyclerView.setHasFixedSize(true);
里面设置了下面的RecyclerView
。正如我的问题中所述,通过这样做,位置不会搞砸。