如何使 recyclerview 项目中的多个视图可点击?
How to make multiple views in recyclerview item clickable?
我有这个适配器 class,其中有一个包含列表的对象。
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {
private Context context;
private Shop shop;
public ProductAdapter(Context context, Shop shop) {
this.context = context;
this.shop = shop;
}
@Override
public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.product_row, parent, false);
return new ProductViewHolder(v);
}
@Override
public void onBindViewHolder(ProductViewHolder holder, int position) {
holder.tvProductTitle.setText(shop.products.get(position).getTitle());
holder.tvProductDescription.setText(shop.products.get(position).getDescription());
Glide.with(context)
.load(shop.products.get(position).getImageUrl())
.placeholder(android.R.drawable.ic_menu_upload_you_tube)
.error(android.R.drawable.stat_notify_error)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(holder.ivProduct);
}
@Override
public int getItemCount() {
if (shop.products != null) {
return shop.products.size();
}
return 0;
}
public static class ProductViewHolder extends RecyclerView.ViewHolder {
private TextView tvProductTitle, tvProductDescription;
private ImageView ivProduct;
public ProductViewHolder(View itemView) {
super(itemView);
tvProductTitle = (TextView) itemView.findViewById(R.id.tvProductTitle);
tvProductDescription = (TextView) itemView.findViewById(R.id.tvProductDescription);
ivProduct = (ImageView) itemView.findViewById(R.id.ivProduct);
}
}
public interface ClickListener {
void onClick(View v, int position);
void onLongClick(View v, int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ProductAdapter.ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ProductAdapter.ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = 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 && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildAdapterPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
我在我的片段中使用了这个适配器,我可以在其中单击 recyclerview 中的一个项目,这将打开另一个 activity,其中包含所选产品及其参数。我不想单击整个项目,而是想单击它的一部分(比方说图像视图),这将与现在的操作相同。但是,我还想在 recyclerview 项目本身中放置一个复选框,它将具有不同的功能。目前,我无法在适配器 class 中使用意图。现在的设置方式我只能点击整个项目。我怎样才能让它像我上面解释的那样工作?
public class ProductsFragment extends android.support.v4.app.Fragment {
private RecyclerView rvProduct;
private RecyclerView.LayoutManager layoutManager;
private ProductAdapter productAdapter;
public static ProductsFragment newInstance(Bundle args) {
ProductsFragment fragment = new ProductsFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_products, container, false);
rvProduct = (RecyclerView) v.findViewById(R.id.rvProduct);
rvProduct.setHasFixedSize(true);
layoutManager = new GridLayoutManager(getContext(), 2);
rvProduct.setLayoutManager(layoutManager);
Bundle bundle = getArguments();
final Shop shop = (Shop) bundle.getSerializable("shop");
productAdapter = new ProductAdapter(getContext(), shop);
rvProduct.setAdapter(productAdapter);
productAdapter.notifyDataSetChanged();
rvProduct.addOnItemTouchListener(new ProductAdapter.RecyclerTouchListener(getContext(), rvProduct, new ProductAdapter.ClickListener() {
@Override
public void onClick(View v, int position) {
Intent details = new Intent(getContext(), ProductDetailsActivity.class);
details.putExtra("product", shop.products.get(position));
startActivity(details);
}
@Override
public void onLongClick(View v, int position) {
}
}));
return v;
}
}
编辑:
我已经设法做到了,请告诉我这是否是正确有效的方法:
holder.tvProductTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(context, ProductDetailsActivity.class);
i.putExtra("product", shop.products.get(position));
context.startActivity(i);
}
});
您可以在 public onBindViewHolder 中将点击侦听器添加到膨胀项目的每个相应视图。你考虑过吗?
编辑:好的,这就是您所做的。虽然我不知道效率如何,但这是我会做的方式。
你的做法不对。
当您滚动列表时,您的 onBindViewHolder 将被重复调用,每次都会设置一个新的侦听器。
相反,您应该在 Adapter 的 ViewHolder class 中设置侦听器。并使用 getAdapterPosition() 方法获取被点击的项目的位置。
例如:
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {
private Context context; private Shop shop;
public ProductAdapter(Context context, Shop shop) {
this.context = context;
this.shop = shop;
}
@Override public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.product_row, parent, false);
return new ProductViewHolder(v);
}
@Override public void onBindViewHolder(ProductViewHolder holder, int position) {
holder.tvProductTitle.setText(shop.products.get(position).getTitle());
holder.tvProductDescription.setText(shop.products.get(position).getDescription());
Glide.with(context) .load(shop.products.get(position).getImageUrl()) .placeholder(android.R.drawable.ic_menu_upload_you_tube) .error(android.R.drawable.stat_notify_error) .diskCacheStrategy(DiskCacheStrategy.RESULT) .into(holder.ivProduct);
}
@Override public int getItemCount()
{
if (shop.products != null) {
return shop.products.size();
} return 0;
}
public static class ProductViewHolder extends RecyclerView.ViewHolder {
private TextView tvProductTitle, tvProductDescription;
private ImageView ivProduct;
public ProductViewHolder(View itemView)
{
super(itemView);
tvProductTitle = (TextView) itemView.findViewById(R.id.tvProductTitle);
tvProductDescription = (TextView) itemView.findViewById(R.id.tvProductDescription);
ivProduct = (ImageView) itemView.findViewById(R.id.ivProduct);
// Set onclickListener on image
ivProduct.setOnCliCkListener(new onClickListener(){
@Override
public void onClick(View v){
Intent i = new Intent(context, ProductDetailsActivity.class);
i.putExtra("product",
shop.products.get(getAdapterPosition()));
context.startActivity(i);
}
}
}
}
public interface ClickListener {
void onClick(View v, int position);
void onLongClick(View v, int position);
}
}
我有这个适配器 class,其中有一个包含列表的对象。
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {
private Context context;
private Shop shop;
public ProductAdapter(Context context, Shop shop) {
this.context = context;
this.shop = shop;
}
@Override
public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.product_row, parent, false);
return new ProductViewHolder(v);
}
@Override
public void onBindViewHolder(ProductViewHolder holder, int position) {
holder.tvProductTitle.setText(shop.products.get(position).getTitle());
holder.tvProductDescription.setText(shop.products.get(position).getDescription());
Glide.with(context)
.load(shop.products.get(position).getImageUrl())
.placeholder(android.R.drawable.ic_menu_upload_you_tube)
.error(android.R.drawable.stat_notify_error)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(holder.ivProduct);
}
@Override
public int getItemCount() {
if (shop.products != null) {
return shop.products.size();
}
return 0;
}
public static class ProductViewHolder extends RecyclerView.ViewHolder {
private TextView tvProductTitle, tvProductDescription;
private ImageView ivProduct;
public ProductViewHolder(View itemView) {
super(itemView);
tvProductTitle = (TextView) itemView.findViewById(R.id.tvProductTitle);
tvProductDescription = (TextView) itemView.findViewById(R.id.tvProductDescription);
ivProduct = (ImageView) itemView.findViewById(R.id.ivProduct);
}
}
public interface ClickListener {
void onClick(View v, int position);
void onLongClick(View v, int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ProductAdapter.ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ProductAdapter.ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = 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 && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildAdapterPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
我在我的片段中使用了这个适配器,我可以在其中单击 recyclerview 中的一个项目,这将打开另一个 activity,其中包含所选产品及其参数。我不想单击整个项目,而是想单击它的一部分(比方说图像视图),这将与现在的操作相同。但是,我还想在 recyclerview 项目本身中放置一个复选框,它将具有不同的功能。目前,我无法在适配器 class 中使用意图。现在的设置方式我只能点击整个项目。我怎样才能让它像我上面解释的那样工作?
public class ProductsFragment extends android.support.v4.app.Fragment {
private RecyclerView rvProduct;
private RecyclerView.LayoutManager layoutManager;
private ProductAdapter productAdapter;
public static ProductsFragment newInstance(Bundle args) {
ProductsFragment fragment = new ProductsFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_products, container, false);
rvProduct = (RecyclerView) v.findViewById(R.id.rvProduct);
rvProduct.setHasFixedSize(true);
layoutManager = new GridLayoutManager(getContext(), 2);
rvProduct.setLayoutManager(layoutManager);
Bundle bundle = getArguments();
final Shop shop = (Shop) bundle.getSerializable("shop");
productAdapter = new ProductAdapter(getContext(), shop);
rvProduct.setAdapter(productAdapter);
productAdapter.notifyDataSetChanged();
rvProduct.addOnItemTouchListener(new ProductAdapter.RecyclerTouchListener(getContext(), rvProduct, new ProductAdapter.ClickListener() {
@Override
public void onClick(View v, int position) {
Intent details = new Intent(getContext(), ProductDetailsActivity.class);
details.putExtra("product", shop.products.get(position));
startActivity(details);
}
@Override
public void onLongClick(View v, int position) {
}
}));
return v;
}
}
编辑: 我已经设法做到了,请告诉我这是否是正确有效的方法:
holder.tvProductTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(context, ProductDetailsActivity.class);
i.putExtra("product", shop.products.get(position));
context.startActivity(i);
}
});
您可以在 public onBindViewHolder 中将点击侦听器添加到膨胀项目的每个相应视图。你考虑过吗?
编辑:好的,这就是您所做的。虽然我不知道效率如何,但这是我会做的方式。
你的做法不对。 当您滚动列表时,您的 onBindViewHolder 将被重复调用,每次都会设置一个新的侦听器。
相反,您应该在 Adapter 的 ViewHolder class 中设置侦听器。并使用 getAdapterPosition() 方法获取被点击的项目的位置。 例如:
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {
private Context context; private Shop shop;
public ProductAdapter(Context context, Shop shop) {
this.context = context;
this.shop = shop;
}
@Override public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.product_row, parent, false);
return new ProductViewHolder(v);
}
@Override public void onBindViewHolder(ProductViewHolder holder, int position) {
holder.tvProductTitle.setText(shop.products.get(position).getTitle());
holder.tvProductDescription.setText(shop.products.get(position).getDescription());
Glide.with(context) .load(shop.products.get(position).getImageUrl()) .placeholder(android.R.drawable.ic_menu_upload_you_tube) .error(android.R.drawable.stat_notify_error) .diskCacheStrategy(DiskCacheStrategy.RESULT) .into(holder.ivProduct);
}
@Override public int getItemCount()
{
if (shop.products != null) {
return shop.products.size();
} return 0;
}
public static class ProductViewHolder extends RecyclerView.ViewHolder {
private TextView tvProductTitle, tvProductDescription;
private ImageView ivProduct;
public ProductViewHolder(View itemView)
{
super(itemView);
tvProductTitle = (TextView) itemView.findViewById(R.id.tvProductTitle);
tvProductDescription = (TextView) itemView.findViewById(R.id.tvProductDescription);
ivProduct = (ImageView) itemView.findViewById(R.id.ivProduct);
// Set onclickListener on image
ivProduct.setOnCliCkListener(new onClickListener(){
@Override
public void onClick(View v){
Intent i = new Intent(context, ProductDetailsActivity.class);
i.putExtra("product",
shop.products.get(getAdapterPosition()));
context.startActivity(i);
}
}
}
}
public interface ClickListener {
void onClick(View v, int position);
void onLongClick(View v, int position);
}
}