If someone can help me. I've a RecyclerView with items but when i try to select ONE item, i can select many items. I think that the problem is in the onClick callback but i don't know exactly. This is the adapter code:
public class HorizontalRecyclerViewAdapter extends RecyclerView
.Adapter<HorizontalRecyclerViewAdapter
.DataObjectHolder> {
private ArrayList<HorizontalData> mDataset;
private static MyClickListener myClickListener;
private SparseBooleanArray selectedItem = new SparseBooleanArray();
public class DataObjectHolder extends RecyclerView.ViewHolder
implements View
.OnClickListener {
TextView mLabel;
TextView mDateTime;
LinearLayout linearLayout;
public DataObjectHolder(View itemView) {
super(itemView);
mLabel = (TextView) itemView.findViewById(R.id.item_list_view_text_view);
mDateTime = (TextView) itemView.findViewById(R.id.item_list_view_text_view_two);
linearLayout = (LinearLayout) itemView.findViewById(R.id.myBackground);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (selectedItem.get(getAdapterPosition(), false)) {
selectedItem.delete(getAdapterPosition());
v.setSelected(false);
} else {
selectedItem.put(getAdapterPosition(), true);
v.setSelected(true);
}
myClickListener.onItemClick(getAdapterPosition(), v);
}
}
public void setOnItemClickListener(MyClickListener myClickListener) {
this.myClickListener = myClickListener;
}
public HorizontalRecyclerViewAdapter(ArrayList<HorizontalData> myDataset) {
mDataset = myDataset;
}
#Override
public DataObjectHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.date_item, parent, false);
DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
return dataObjectHolder;
}
#Override
public void onBindViewHolder(DataObjectHolder holder, int position) {
holder.linearLayout.setSelected(selectedItem.get(position, false));
holder.mLabel.setText(mDataset.get(position).getmTitle());
holder.mDateTime.setText(mDataset.get(position).getmSubTitle());
}
#Override
public int getItemCount() {
return mDataset.size();
}
public interface MyClickListener {
void onItemClick(int position, View v);
}
}
Thanks!
First of all you don't need SparseBooleanArray, because you want only one item to be selected. It'd be enough to have int selectedItemPos with would represent currently selected item position.
Here's a simple adapter that I've just created and it's working, with comments explaining what's happening:
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.ViewHolder> {
private ArrayList<String> items;
//field mentioned before
private int selectedItemPos = -1;
//I create some items to see if my adapter is working.
public TestAdapter() {
this.items = new ArrayList<>();
for (int i=0; i<20; i++) {
items.add("Test" + i);
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false));
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
String item = items.get(position);
holder.mName.setText(item);
//This line sets selection state to true if current position is the same as selected one, and false otherwise.
holder.itemView.setSelected(selectedItemPos == position);
}
#Override
public int getItemCount() {
return items.size();
}
//helper method
protected void setSelectedItem(int position) {
int oldSelected = selectedItemPos;
selectedItemPos = position;
// update view of unselected item
notifyItemChanged(oldSelected);
//update view of just selected item
notifyItemChanged(selectedItemPos);
}
protected class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView mName;
public ViewHolder(View view) {
super(view);
mName = (TextView) view.findViewById(R.id.taskListItem_name);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//if the clicked item is already selected,
// we will just unselect it and no new item will be selected
//(new one is -1, which is none)
int newSelectedItem = getAdapterPosition()==selectedItemPos?-1:getAdapterPosition();
//apply changes on adapter
setSelectedItem(newSelectedItem);
}
}
}
You should be able to easily merge this code with yours.
Related
I'm displaying the list of items in a RecyclerView. If I click on the item name I have to make the tick mark image visible. If i click on the name the image is visible but while I am scrolling the image position is changing continuously. Please can anyone help me to resolve this issue?
Here is my code for RecyclerViewAdapter
public class Category_adapter extends RecyclerView.Adapter<Category_adapter.MyViewHolder> {
Activity context;
boolean sample = false;
ArrayList data = new ArrayList<>();
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView txt_name;
ImageView img_select;
public MyViewHolder(View itemView) {
super(itemView);
txt_name = (TextView)itemView.findViewById(R.id.txt_category_new);
img_select = (ImageView) itemView.findViewById(R.id.img_select);
img_select.setVisibility(View.GONE);
txt_name.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
img_select.setVisibility(View.VISIBLE);
Log.e("name", "Holder Name" + txt_name.getText().toString());
}
});
}
}
public Category_adapter(Activity con, ArrayList data) {
this.data = data;
this.context = con;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.category_adapter, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int listPosition) {
holder.txt_name.setText(data.get(listPosition).toString());
}
#Override
public int getItemCount() {
return data.size() ;
}
}
ArrayList<Boolean> clicked = new ArrayList<>();
and save the value clicked.
and onBindView holder put something like this:
if(clicked.get(position)){
view.setvisiblity(View.VISIBLE);
}else{
view.setvisiblity(View.GONE);
}
I had some problem about scrolling with Card inside RecyclerView. There some additional gaps when I scroll inside the RecyclerView, you can see it in this gif:
This is my adapter. Is this because the fragment or what ?
public class PosItemAdapter extends RecyclerView.Adapter<PosItemAdapter.MyViewHolder> {
private List<Item> itemList;
private ArrayList<CartItem> cartList;
private Boolean isMixed = false;
public class MyViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public ImageView picture;
public TextView name;
public TextView desc;
public TextView price;
public MyViewHolder(View view) {
super(view);
mView = view;
picture = (ImageView) view.findViewById(R.id.list_pos_item_picture);
name = (TextView) view.findViewById(R.id.list_pos_item_name);
price = (TextView) view.findViewById(R.id.list_pos_item_price);
}
}
public PosItemAdapter(ArrayList<Item> itemList, Boolean isMixed) {
this.itemList = itemList;
this.isMixed = isMixed;
}
public Item getValueAt(int position) {
return itemList.get(position);
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_pos_item_layout, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
#Override
public int getItemCount() {
if (itemList != null) {
return itemList.size();
} else {
return 0;
}
}
}
Solved, the problem was my card height. I set to wrap_content and the glitch fixed.
In RecyclerView.Adapter i need to change favIcon in each row list that after select each position just specified row favIcon change.
All thing is right but when scroll RecyclerView , position of selected row change automatically!
it's my adapter class :
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ItemData[] itemsData;
Activity activity;
public MyAdapter(Activity activity, ItemData[] itemsData) {
this.activity=activity;
this.itemsData = itemsData;
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout, null);
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
viewHolder.txtViewTitle.setText(itemsData[position].getTitle());
viewHolder.imgViewIcon.setImageResource(itemsData[position].getImageUrl());
viewHolder.imgViewIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!viewHolder.isFav) {
Toast.makeText(activity,"Selected Row : "+position,Toast.LENGTH_SHORT).show();
viewHolder.isFav = true;
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
} else {
viewHolder.imgViewIcon.setImageResource(R.drawable.pre_ic_ab_drawer);
viewHolder.isFav = false;
}
}
});
if (viewHolder.isFav)
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public Boolean isFav=false;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
}
#Override
public int getItemCount() {
return itemsData.length;
}
}
What I see in the output :
As seen i select first row icon , but after scroll RecyclerView , selected position change.
Then try to use changing favIconand imgViewIcon.setOnClickListener in onCreateViewHolder again wrong position!
Too i try to store position in sharedPreferences or modelClass , but this return wrong position in scrolling yet
There is a way to avoid this problem?
I saw this solution Too :Get clicked item and its position in RecyclerView
Try to use your model ItemData[] itemsData; to save if element is selected.
eg.
if (itemsData[position].isFav){
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
}else{
viewHolder.imgViewIcon.setImageResource(R.drawable.pre_ic_ab_drawer);
}
viewHolder.imgViewIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!itemsData[position].isFav) {
Toast.makeText(activity,"Selected Row : "+position,Toast.LENGTH_SHORT).show();
itemsData[position].isFav = true;
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
} else {
viewHolder.imgViewIcon.setImageResource(R.drawable.pre_ic_ab_drawer);
itemsData[position].isFav = false;
}
}
});
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ItemData[] itemsData;
Activity activity;
public MyAdapter(Activity activity, ItemData[] itemsData) {
this.activity=activity;
this.itemsData = itemsData;
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout, null);
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
viewHolder.txtViewTitle.setText(itemsData[position].getTitle());
viewHolder.imgViewIcon.setImageResource(itemsData[position].getImageUrl());
viewHolder.imgViewIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!viewHolder.isFav) {
Toast.makeText(activity,"Selected Row : "+position,Toast.LENGTH_SHORT).show();
viewHolder.isFav = true;
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
} else {
viewHolder.imgViewIcon.setImageResource(R.drawable.pre_ic_ab_drawer);
viewHolder.isFav = false;
}
}
});
if (viewHolder.isFav)
viewHolder.imgViewIcon.setImageResource(R.drawable.icon_fav);
else
// The change
viewHolder.imgViewIcon.setImageResource(R.drawable.pre_ic_ab_drawer);
}
When you bind the ViewHolder you should reset the ImageView icon if it's not fav.
I have an array of 600 items. I have put all the array items in a RecyclerView and they are scrolling well. But, when I try to access onClick listener it is not getting called. I also tried to Implement View.OnClickListener and Override onClick in my ViewHolder class, but its not working.
I want to Toast data of the clicked item in the list when user clicks one of the items in the view
Adapter code is
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private String mItem;
private TextView mTextView;
public ViewHolder(View view) {
super(view);
view.setOnClickListener(this);
mTextView = (TextView) view.findViewById(R.id.item_title);
}
public void setItem(String item) {
mItem = item;
mTextView.setText(item);
}
#Override
public void onClick(View view) {
Log.d("TAG", "onClick " + getPosition() + " " + mItem);
}
}
private String[] mDataset;
public MyAdapter(String[] dataset) {
mDataset = dataset;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setItem(mDataset[position]);
}
#Override
public int getItemCount() {
return mDataset.length;
}
}
Try this..
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder
{
private String mItem;
private TextView mTextView;
public ViewHolder(View view) {
super(view);
mTextView = (TextView) view.findViewById(R.id.item_title);
}
public void setItem(String item) {
mItem = item;
mTextView.setText(item);
}
private String[] mDataset;
Context context;
public MyAdapter(Context context,String[] dataset) {
this.context=context;
mDataset = dataset;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setOnClickListener(new ItemClicklistener(position);
holder.setItem(mDataset[position]);
}
#Override
public int getItemCount() {
return mDataset.length;
}
class ItemClicklistener implements View.OnClickListener {
private int position;
ItemClicklistener(int position) {
this.position = position;
}
#Override
public void onClick(View view) {
Toast.makeText(context,"OnClick :"+position,Toast.LENGTH_SHORT).show();
}
}
}
public class MyAdapter extends RecyclerView.Adapter {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private List<MyModel> list;
View v1;
RecyclerView.ViewHolder vh;
public MyAdapter(List<MyModel> lists) {
list = lists;
}
#Override
public int getItemViewType(int position) {
return list.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
if (viewType == VIEW_ITEM) {
v1 = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item, parent, false);
vh = new MyViewHolder(v1);
return vh;
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MyViewHolder) {
final MyModel mymodel= (MyModel) list.get(position);
((MyViewHolder) holder).mTextView.setText(mymodel.getItem());
((MyViewHolder) holder).mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("TAG", "onClick " + Integer.toString(position) + " " + mymodel.getItem());
}
});
}
}
#Override
public int getItemCount() {
return list.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
public TextView;
public MyViewHolder(View view) {
super(view);
mTextView = (TextView) view.findViewById(R.id.item_title);
}
}
}
// List Item Stored
public class MyModel extends Application implements Serializable {
private static final long serialVersionUID = 1L;
private String item,
public MyModel() {}
public MyModel(String itemtext) {
this.item = itemtext;
}
public String getItem() {return item;}
public void setItem(String id){ this.item = item;}
}
//use this code in main activity
List<MyModel> Listitem = new ArrayList<CarListGetterSetter>();
for(int i=0;i<600;i++){
Listitem.add(new MyModel("hi"+i);
}
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
MyAdapter mAdapter = new MyAdapter(Listitem);
recyclerView.setAdapter(mAdapter);
You can implement your RecyclerView adapter this way to support for onItemCLick and OnItemLongClick
public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder>{
ArrayList<Person> data;
Context context;
HashMap<String, Integer> screenDetails;
private static ClickListener clickListener;
public interface ClickListener {
void onItemClick(int position, View v);
void onItemLongClick(int position, View v);
}
public void setOnItemClickListener(ClickListener clickListener) {
PersonAdapter.clickListener = clickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
public View view;
TextView full_name;
public ViewHolder(View v) {
super(v);
view = v;
full_name = (TextView)view.findViewById(R.id.first_name);
v.setOnClickListener(this);
v.setOnLongClickListener(this);
}
#Override
public void onClick(View v) {
clickListener.onItemClick(getAdapterPosition(), v);
}
#Override
public boolean onLongClick(View v) {
clickListener.onItemLongClick(getAdapterPosition(), v);
return false;
}
}
public PersonAdapter(Context context, ArrayList<Person> data) {
this.context = context;
this.data = data;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View cardView = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_chatroom_item, parent, false);
return new ViewHolder(cardView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Person person = data.get(position);
}
#Override
public int getItemCount() {
return data.size();
}
}
And in your activity implement it this way
PersonAdapter personAdapter = new PersonAdapter(getApplicationContext(),persons);
personAdapter.setOnItemClickListener(new PersonAdapter.ClickListener() {
#Override
public void onItemClick(int position, View v) {
}
#Override
public void onItemLongClick(int position, View v) {
}
});
recyclerView.setAdapter(PersonAdapter);
On click of button when I'm scrolling the view, it changes the
position of that clicked button. On every scroll it's showing different
position.
public class ProductAdapter extends
RecyclerView.Adapter<ProductAdapter.ProductViewHolder> {
Context ctx;
ArrayList<ProductDetail> productList;
public ProductAdapter(Context ctx, ArrayList<ProductDetail> productList) {
this.ctx = ctx;
this.productList = productList;
}
#Override
public int getItemCount() {
return productList.size();
}
#Override
public void onBindViewHolder(final ProductViewHolder vHolder, int pos) {
vHolder.txt_prod_name.setText(productList.get(pos).getProduct_desc());
vHolder.btn_add.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
vHolder.lyt_prod_qty.setVisibility(View.VISIBLE);
vHolder.btn_add.setVisibility(View.GONE);
}
});
}
#Override
public ProductViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.activity_recycler_search_item, null);
ProductViewHolder viewHolder = new ProductViewHolder(view);
return viewHolder;
}
public class ProductViewHolder extends RecyclerView.ViewHolder {
TextView txt_prod_name;
TextView txt_delivery_type;
TextView txt_prod_mrp;
Spinner spn_prod_qty;
LinearLayout list_lyt, lyt_prod_qty;
Button btn_add;
public ProductViewHolder(View itemView) {
super(itemView);
txt_prod_name = (TextView) itemView
.findViewById(R.id.txt_prod_name);
txt_delivery_type = (TextView) itemView
.findViewById(R.id.txt_delivery_type);
txt_prod_mrp = (TextView) itemView.findViewById(R.id.txt_prod_mrp);
btn_add = (Button) itemView.findViewById(R.id.btn_add);
lyt_prod_qty = (LinearLayout) itemView
.findViewById(R.id.lyt_prod_qty);
}
}
}
On click of Button when I'mm scrolling the view, it changes the position of that clicked button. On every scroll it's showing different
position. Where should I out my click logic or should refresh the adapter every time?
In your ProductDetail modal class add a member boolean isButtonClicked; and add its getter and setter as well. Then make following changes in your onBindViewHolder method:
#Override
public void onBindViewHolder(final ProductViewHolder vHolder, int pos) {
final ProductDetail productDetail = productList.get(pos);
vHolder.txt_prod_name.setText(productDetail.getProduct_desc());
if(productDetail.isButtonClicked()){
vHolder.lyt_prod_qty.setVisibility(View.VISIBLE);
vHolder.btn_add.setVisibility(View.GONE);
} else {
vHolder.lyt_prod_qty.setVisibility(View.GONE);
vHolder.btn_add.setVisibility(View.VISIBLE);
}
vHolder.btn_add.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
vHolder.lyt_prod_qty.setVisibility(View.VISIBLE);
vHolder.btn_add.setVisibility(View.GONE);
productDetail.setIsButtonClicked(true);
}
});
}