Removing item from RecyclerView - android

I am having trouble removing items from RecyclerView. When I click on delete, the item is removed from RecyclerView, but comes back when I open the app again. I'm hoping it is just a minor issue that someone here can point out or direct me to what area to troubleshoot. The removeItem(String item) in bold is what I think is the issue. You can't see it in this post, but it is "not used".
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
private List<Grocery> mListData;
private SQLGroceryHelper helper;
RecyclerViewAdapter adapter;
//Adapter's Constructor//
public RecyclerViewAdapter(List<Grocery> mDataList) {
this.mListData = mDataList;
}
//Provide a reference to the views for each contact item//
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView rowItem;
ImageButton purchasedButton;
ImageButton deleteButton;
LinearLayout linearLayout;
public MyViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView.findViewById(R.id.recycler_row);
rowItem = (TextView) itemView.findViewById(R.id.item_field1);
purchasedButton = (ImageButton) itemView.findViewById(R.id.item_purchased);
deleteButton = (ImageButton) itemView.findViewById(R.id.delete_item);
}
}
//Inflate the view based on the viewtype provided//
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Create a new view by inflating the row item xml//
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row, parent, false);
//Set the view to the ViewHolder//
MyViewHolder holder = new MyViewHolder(row);
return holder;
}
//Display data at the specified position//
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.rowItem.setText(mListData.get(position).getTextItem());
holder.purchasedButton.setOnClickListener(new View.OnClickListener() {
//Ignore this click for now//
#Override
public void onClick(View v) {
removeItem(position);
}
});
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
removeItem(position);
}
});
}
public void **removeItem**(String item) {
int position = mListData.indexOf(item);
if (position != -1) {
mListData.remove(item);
notifyItemRemoved(position);
}
}
public void removeItem(int position) {
mListData.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
if (mListData == null) {
return 0;
}
return mListData.size();
}
}

You are removing the data from local object, mListData I guess the original data object remains intact. Remove the data item from the original data object as well
Declare a interface
public interface AdapterCommunication{
void removeStringItem(int position);
}
then in your adapter
private AdapterCommunication mListener;
public void setOnClickListener(AdapterCommunication listener){
mListener = listener;
}
Then from your activity where you initialize the adapter
RecyclerViewAdapter adapter = new RecyclerViewAdapter(list);
adapter.setOnClickListener(new AdapterCommunication{
public void removeStringItem(int position){
list.remove(position);
adapter.notifyDataSetChanged();
}
});
In your adaper,
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.remove(position);
}
});

Related

I want to make my buttons in recyclerView toggleable means when clicked on one other all should be dssleted

when i click on one button others should be deselected how to achieve this
I have seen other answers in stack but none solved my problem or i was not able to undrestand properly
public class LocationAreaAdapter extends RecyclerView.Adapter<LocationAreaAdapter.ViewHolder> {
private int mSelectedItem = -1;
private ArrayList<String> mNames = new ArrayList<>();
private Context mContext;
private ArrayList<Boolean> isChecked=new ArrayList<>();
private AdapterView.OnItemClickListener onItemClickListener;
public LocationAreaAdapter(Context context,ArrayList<String> mNames ){
this.mContext=context;
this.mNames=mNames;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.locatin_area_cardview, viewGroup, false);
return new ViewHolder(view,this);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int i) {
holder.name.setText(mNames.get(i));
holder.name.setChecked(i == mSelectedItem);
//what to do here
}
#Override
public int getItemCount() {
return mNames.size();
}
public void onItemHolderClick(ViewHolder holder) {
if (onItemClickListener != null)
onItemClickListener.onItemClick(null, holder.itemView, holder.getAdapterPosition(), holder.getItemId());
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
RadioButton name;
LocationAreaAdapter mAdapter;
public ViewHolder(View itemView, final LocationAreaAdapter mAdapter) {
super(itemView);
this.mAdapter = mAdapter;
name = itemView.findViewById(R.id.location_area_button);
itemView.setOnClickListener(this);
name.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mSelectedItem = getAdapterPosition();
notifyItemRangeChanged(0, mNames.size());
mAdapter.onItemHolderClick(ViewHolder.this);
}
}
}
when i click on the button the button is not clicked rather recyclerview flashes
When you click to viewholder item select position of current and deselect other viewholder position:
holder.name.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mSelectedItem = position;
notifyDataSetChanged();
}
});
if (mSelectedItem==position ) {
//viewHolder.item.setVisibility(View.VISIBLE);
show itew here.
} else {
// viewHolder.item.setVisibility(View.GONE);
hideitew here.
}

Disabling a RecyclerView

I'm facing the next problem.
I have a RecyclerView with the Adapter, the items, etc.
What I need is: Select an item in the recycler, change the color of that item, and then I have to disable the rest of the other items. It's like a RadioButton list.
I select one and disable the others. If I select again the same item, enable all the list.
I already have the onClick Button listener. I need to know if I have to reload again de list, If I have to loop and disable item by item, etc.
Thanks
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Human> humans;
private HumanClick selectedHuman;
#Inject
public MyAdapter() {
}
public void init(List<Human> humanList, SelectedHumanClick humanClick){
this.humans = humanList;
this.humanClick = humanClick;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_Human, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
final Human human = Humans.get(position);
holder.bind(Humans.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedHumanClick.onSelectedHumanClick(Human);
}
});
}
#Override
public int getItemCount() {
return humans != null ? Humans.size() : 0;
}
public final class MyViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.text_view_human_name)
TextView textView;
#BindView(R.id.image_view_profile)
ImageView imageViewProf;
#BindView(R.id.image_view_radio_btn)
ImageView imageViewRB;
private boolean isChecked = false;
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(final Human Human) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
humanClick.onSelectedHumanClick(Human);
}
});
textView.setText(human.getName());
}
public void changeRBImage() {
if(!isChecked){
isChecked = true;
imageViewRB.setBackground(ContextCompat.getDrawable(imageViewRB.getContext(), R.drawable.selected));
}
else{
isChecked = false;
imageViewRB.setBackground(ContextCompat.getDrawable(imageViewRB.getContext(), R.drawable.not_selected));
}
}
}
My Recycler is defined inside a fragment here:
public class HumansFragment implenets HumanClick{
#BindView(R.id.recycler_humans)
RecyclerView humansRecyclerView;
#Inject
MyAdapter myAdapter;
.
.
.
public void loadHumans(List<Human> humans) {
myAdapter.init(Humans, this);
humansRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
humansRecyclerView.setAdapter(myAdapter);
}
#Override
public void humansClick(Human human) {
//TODO
}
}
I'm thinking in something like this, using setOnItemClickListener and check the position of the item clicked. The position is the index of the item clicked check the last event and new, if both are equal change color, if not dont do anything like disabling.
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textView = (TextView)view.findViewById(android.R.id.text1);
}
#Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();
//go through each item if you have few items within recycler view
if(getLayoutPosition()==0){
//Do whatever you want here
}else if(getLayoutPosition()==1){
//Do whatever you want here
}else if(getLayoutPosition()==2){
}else if(getLayoutPosition()==3){
}else if(getLayoutPosition()==4){
}else if(getLayoutPosition()==5){
}
//or you can use For loop if you have long list of items. Use its length or size of the list as
for(int i = 0; i<exampleList.size(); i++){
}
}
}
Or something smaller
RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(context, recyclerView ,new
RecyclerItemClickListener.OnItemClickListener() {
#Override public void onItemClick(View view, int position) {
// do whatever
}
#Override public void onLongItemClick(View view, int position) {
// do whatever
}
})
);

RecyclerView get View by position

I have a RecyclerView and each CardView contains a TextView and an ImageView. Whenever I click an item, I want to set the image visibility to VISIBLE and to set the previous clicked item image's visibility to INVISIBLE.
This is my Adapter class :
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder>{
private Context context;
private List<Category> lista;
private LayoutInflater layoutInflater;
private IncomeCategoryActivity activity;
private static final int CATEGORY_REQUEST=6;
private static final int ITEM_EDIT=1;
private static final int ITEM_DELETE=2;
private static final int EDIT_REQUEST=7;
private int current_pos=-1;
public CategoryAdapter(List<Category> lista, Context context, IncomeCategoryActivity activity) {
this.context = context;
this.lista = lista;
this.activity=activity;
layoutInflater=LayoutInflater.from(context);
}
#Override
public CategoryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view=layoutInflater.inflate(R.layout.category_layout, parent, false);
ViewHolder viewHolder=new ViewHolder(view, activity);
return viewHolder;
}
#Override
public void onBindViewHolder(CategoryAdapter.ViewHolder holder, int position) {
holder.imageView.setImageURI(lista.get(position).getUri());
holder.textView.setText(lista.get(position).getCategory());
holder.position = position;
holder.category=lista.get(position);
if(holder.category.isChecked()==true){
holder.imageViewCheck.setVisibility(View.VISIBLE);
current_pos=position;
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
}
#Override
public int getItemCount() {
return lista.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener{
public ImageView imageView;
public TextView textView;
public ImageView imageViewCheck;
public int position;
public Category category;
public IncomeCategoryActivity activity;
public ViewHolder(View itemView, IncomeCategoryActivity activity) {
super(itemView);
this.activity=activity;
imageView=itemView.findViewById(R.id.customCategoryImageView);
textView=itemView.findViewById(R.id.customCategoryTextView);
imageViewCheck=itemView.findViewById(R.id.customCheckImageView);
itemView.setOnClickListener(this);
itemView.setOnCreateContextMenuListener(this);
}
#Override
public void onClick(View v) {
String aux=textView.getText().toString();
if(aux=="CATEGORIE NOUĂ"){
Intent intent=new Intent(context, CustomIncomeActivity.class);
activity.startActivityForResult(intent, CATEGORY_REQUEST);
}
else{
imageViewCheck.setVisibility(View.VISIBLE);
int pozitie_check=getLayoutPosition();
Intent intent=new Intent(context, AddIncomeActivity.class);
intent.putExtra("categorie_venit", aux);
intent.putExtra("position_check", pozitie_check);
activity.setResult(Activity.RESULT_OK, intent);
activity.finish();
}
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Selectează acțiunea");
MenuItem edit=menu.add(0, ITEM_EDIT, 0, "Modifică");
MenuItem delete=menu.add(0, ITEM_DELETE, 0, "Șterge");
edit.setOnMenuItemClickListener(this);
delete.setOnMenuItemClickListener(this);
}
#Override
public boolean onMenuItemClick(MenuItem item) {
int position=getLayoutPosition();
if (item.getGroupId() == 0) {
if(item.getItemId()==ITEM_EDIT){
Category category=lista.get(position);
Intent intent=new Intent(activity, CustomIncomeActivity.class);
intent.putExtra("edit_icon", category.getUri());
intent.putExtra("edit_category", category.getCategory());
intent.putExtra("list_position", position);
activity.startActivityForResult(intent, EDIT_REQUEST);
}
else if(item.getItemId()==ITEM_DELETE){
lista.remove(position);
notifyDataSetChanged();
}
}
return true;
}
At this moment, whenever I click an item, there are two images VISIBLE on the RecyclerView: the clicked item's image and the previous clicked item's image. I think I need to get the previous View by its position and to manually set the visibility to INVISIBLE.
recycleView.getChildCount() and recycleView_parent.getChildAt() only gives the Adapter items which is shows only screen .
that means if your list has 200 items and the only 5 items shows on screen so we can find only 5 item with the help of recycleView
i am using one simple trick to solve the issue.
You can define Hashmap which hold your holder objects
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
ArrayList<Model> dataList;
Context context;
HashMap<Integer,ViewHolder> holderlist;
public MyAdapter(ArrayList<Model> dataList, Context context) {
this.context = context;
this.dataList = dataList;
holderlist = new HashMap<>();
}
And after that to save the holder in Hashmap
public void onBindViewHolder(final ViewHolder holder, final int position) {
if(!holderlist.containsKey(position)){
holderlist.put(position,holder);
}
Create a method in Adapter.
public MyListAdapter.ViewHolder getViewByPosition(int position) {
return holderlist.get(position);
}
Call this method from your Activity or whenever you want.
for (int i = 0; i < datalList.size(); i++) {
MyAdapter.ViewHolder holder = ((MyAdapter)recycleView.getAdapter()).getViewByPosition(i);
View view = holder.itemView;
TextView tv = view.findViewById(R.id.tv);
}
I have created the demo you can refer it and implement for single selection
recyclerView.setAdapter(new RecyclerView.Adapter() {
int selected_position = -1;
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(
R.layout.row_color_list,parent,false)) {
#Override
public String toString() {
return super.toString();
}
};
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
ImageView imageView = holder.itemView.findViewById(R.id.image);
if(selected_position == position){
imageView.setVisibility(View.VISIBLE);
}else {
imageView.setVisibility(View.GONE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selected_position != holder.getAdapterPosition()){
selected_position = holder.getAdapterPosition();
notifyDataSetChanged();
}
}
});
}
#Override
public int getItemCount() {
return 20;
}
});
You can do as following:
1) Declare a global variable:
private int selectedPos = -100; // Put any irrelevant number you want
2) Set selected position onClick() :
#Override
public void onClick(View v) {
selectedPos = getAdapterPosition();
}
3) Check selected postion and assign visibility inside onBindViewHolder():
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
if(position == selectedPos){
holder.imageViewCheck.setVisibility(View.VISIBLE);
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
}
Try this code..
add this code into adapter class for handling click event..
OnItemClick onItemClick;
public void setOnItemClick(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public interface OnItemClick {
void getPosition(String data); //pass any data to shared it.
}
after bind method..
#Override
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
// below code handle click event on recycler view item.
final String str=mStringList.get(position); // here your boject
if(holder.category.isChecked()==true){
holder.imageViewCheck.setVisibility(View.VISIBLE);
current_pos=position;
} else {
holder.imageViewCheck.setVisibility(View.INVISIBLE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.getPosition(str); // pass your data.
}
});
}
after bind adapter into recycler view it means adapter not null then called below code..
adpater.setOnItemClick(new RecyclerViewAdpater.OnItemClick() {
#Override
public void getPosition(String data) {
// hear update your value for check into if condition.
data="sdfsdf";
adpater.notifyDataSetChanged();
}
});
and also read comments and also try to make custon class and access that object value and update after click it..
this code only how to handle click event into recycler view.

my onClickListener on my recyclerView doesn't get called what can be the reasion

i made a onClickListener for my recyclerView but it just didn't work.
When i click an item from the recyclerView the log doesnt appear, the commands i put in the OnClickListener arent called ,i spend already 2-3 days to find the problem but i didn't see something wrong in my code it should cost the problem, probably its a small stupid mistake
but pls if anyone can help me get the problem i will be very happy.
In my adapter class i assigned the onClick to check and uncheck a checkbox
and in the MainActivity i assigned to save it in the dataBase
this is in my main activity
private void setUpGUI() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
cardView = (CardView) findViewById(R.id.cardView);
recyclerView = (RecyclerView) findViewById(R.id.recylerView);
adapter = new ItemAdapter(new ItemAdapter.ItemClickListener() {
#Override
public void onItemClicked(TodoItem item) {
Log.d(TAG, "on item click");
Uri uri = Uri.parse(TodoItemsContentProvider.CONTENT_URI + "/" + item.getId());
getContentResolver().update(uri, item.toContentValues(), null, null);
}
});
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showAddItemPopup();
}
});
this is my adapter class
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
private static final String TAG = "item adapter";
private List<TodoItem> items = new ArrayList<>();
private ItemClickListener itemClickListener;
public ItemAdapter(ItemClickListener listener) {
itemClickListener = listener;
}
public void addItem(TodoItem item) {
if (!items.contains(item)) {
items.add(item);
Collections.sort(items);
notifyItemInserted(items.indexOf(item));
}
}
public void addItems(Collection<TodoItem> newItems) {
for (TodoItem item : newItems) {
if (!items.contains(item)) {
items.add(item);
}
}
Collections.sort(items);
notifyDataSetChanged();
}
public TodoItem getItem(int position) {
return items.get(position);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
}
// This listener listens for clicks to the viewholder. The viewholder passes back the position it is.
private final ClickListener clickListener = new ClickListener() {
#Override
public void onItemClicked(int position) {
Log.d(TAG, "on click adapter");
// Get the item that was clicked
TodoItem item = items.get(position);
// Set the completed state
item.setCompleted(!item.isCompleted());
//Update the UI
notifyItemChanged(position);
// Pass the item back the the itemclicklistener
itemClickListener.onItemClicked(item);
}
};
#Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_list_item, parent, false);
return new ViewHolder(v, clickListener);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
TodoItem item = items.get(position);
holder.textView.setText(item.getText());
holder.subTextViewA.setText(item.getSubText());
holder.checkBox.setChecked(item.isCompleted());
//holder.backgroundLayout.setBackgroundColor(Color.parseColor("#ec48e418"));
}
#Override
public int getItemCount() {
return items.size();
}
// The view holder listens to clicks on the
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// private RelativeLayout backgroundLayout;
final TextView textView, subTextViewA;
final CheckBox checkBox;
final ClickListener clickListener;
public ViewHolder(View itemView, ClickListener clickListener) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textView);
subTextViewA = (TextView) itemView.findViewById(R.id.subTextViewA);
checkBox = (CheckBox) itemView.findViewById(R.id.checkBox);
//backgroundLayout = (RelativeLayout) itemView.findViewById(R.id.backgroundLayout);
itemView.setOnClickListener(this);
this.clickListener = clickListener;
}
#Override
public void onClick(View v) {
clickListener.onItemClicked(getAdapterPosition());
}
}
// Private listener fot the adapter to know about view clicks
private interface ClickListener {
void onItemClicked(int position);
}
// Public listener to pass the item back to the activity
public interface ItemClickListener {
void onItemClicked(TodoItem item);
}
}
When you click on your checkox, itemView.OnClickListener does not invoke. http://screencast.com/t/moP30Lfc49X
You can set click listener for checkbox and save (or remove) items from database like that http://screencast.com/t/Iw1K3Ld8nna
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemClickListener.onItemClick(item, holder.checkBox.isChecked());
}
});
public interface OnItemClickListener {
void onItemClick(MainActivity.Item item, boolean save);
}
In your activity:
adapter.setOnItemClickListener(new RecyclerViewAdapter.OnItemClickListener() {
#Override
public void onItemClick(Item item, boolean save) {
if (save) {
// Save
} else {
// Remove from db
}
}
});

How do I get the position selected in a RecyclerView?

I am experimenting with the support library's recyclerview and cards. I have a recyclerview of cards. Each card has an 'x' icon at the top right corner to remove it:
The card xml, list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/taskDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="40sp"
android:text="hi"/>
<ImageView
android:id="#+id/xImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:src="#drawable/ic_remove"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
I attempted to tag the row with the position I would use in notifyItemRemoved(position) in TaskAdapter.java:
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder> {
private List<Task> taskList;
private TaskAdapter thisAdapter = this;
// cache of views to reduce number of findViewById calls
public static class TaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
protected TextView taskTV;
protected ImageView closeBtn;
public TaskViewHolder(View v) {
super(v);
taskTV = (TextView)v.findViewById(R.id.taskDesc);
}
#Override
public void onClick(View v) {
int position = v.getTag();
adapter.notifyItemRemoved(position);
}
}
public TaskAdapter(List<Task> tasks) {
if(tasks == null)
throw new IllegalArgumentException("tasks cannot be null");
taskList = tasks;
}
// onBindViewHolder binds a model to a viewholder
#Override
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) {
final int position = pos;
Task currTask = taskList.get(pos);
taskViewHolder.taskTV.setText(currTask.getDescription());
taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thisAdapter.notifyItemRemoved(position);
}
});
}
#Override
public int getItemCount() {
return taskList.size();
}
// inflates row to create a viewHolder
#Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos) {
View itemView = LayoutInflater.from(parent.getContext()).
inflate(R.layout.list_item, parent, false);
return new TaskViewHolder(itemView);
}
}
This won't work because you can't set a tag nor can I access the adapter from onClick.
Set your onClickListeners on onBindViewHolder() and you can access the position from there. If you set them in your ViewHolder you won't know what position was clicked unless you also pass the position into the ViewHolder
EDIT
As pskink pointed out ViewHolder has a getPosition() so the way you were originally doing it was correct.
When the view is clicked you can use getPosition() in your ViewHolder and it returns the position
Update
getPosition() is now deprecated and replaced with getAdapterPosition()
Update 2020
getAdapterPosition() is now deprecated and replaced with getAbsoluteAdapterPosition() or getBindingAdapterPosition()
Kotlin code:
override fun onBindViewHolder(holder: MyHolder, position: Int) {
// - get element from your dataset at this position
val item = myDataset.get(holder.absoluteAdapterPosition)
}
A different method - using setTag() and getTag() methods of the View class.
use setTag() in the onBindViewHolder method of your adapter
#Override
public void onBindViewHolder(myViewHolder viewHolder, int position) {
viewHolder.mCardView.setTag(position);
}
where mCardView is defined in the myViewHolder class
private class myViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public View mCardView;
public myViewHolder(View view) {
super(view);
mCardView = (CardView) view.findViewById(R.id.card_view);
mCardView.setOnClickListener(this);
}
}
use getTag() in your OnClickListener implementation
#Override
public void onClick(View view) {
int position = (int) view.getTag();
//display toast with position of cardview in recyclerview list upon click
Toast.makeText(view.getContext(),Integer.toString(position),Toast.LENGTH_SHORT).show();
}
see https://stackoverflow.com/a/33027953/4658957 for more details
To complement #tyczj answer:
Generic Adapter Pseido code:
public abstract class GenericRecycleAdapter<T, K extends RecyclerView.ViewHolder> extends RecyclerView.Adapter{
private List<T> mList;
//default implementation code
public abstract int getLayout();
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(getLayout(), parent, false);
return getCustomHolder(v);
}
public Holders.TextImageHolder getCustomHolder(View v) {
return new Holders.TextImageHolder(v){
#Override
public void onClick(View v) {
onItem(mList.get(this.getAdapterPosition()));
}
};
}
abstract void onItem(T t);
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
onSet(mList.get(position), (K) holder);
}
public abstract void onSet(T item, K holder);
}
ViewHolder:
public class Holders {
public static class TextImageHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView text;
public TextImageHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.text);
text.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
}
}
Adapter usage:
public class CategoriesAdapter extends GenericRecycleAdapter<Category, Holders.TextImageHolder> {
public CategoriesAdapter(List<Category> list, Context context) {
super(list, context);
}
#Override
void onItem(Category category) {
}
#Override
public int getLayout() {
return R.layout.categories_row;
}
#Override
public void onSet(Category item, Holders.TextImageHolder holder) {
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
FrameLayout root;
public ViewHolder(View itemView) {
super(itemView);
root = (FrameLayout) itemView.findViewById(R.id.root);
root.setOnClickListener(this);
}
#Override
public void onClick(View v) {
LogUtils.errorLog("POS_CLICKED: ",""+getAdapterPosition());
}
}
Get focused child, and use it to get position in adapter.
mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())
Personally, the simplest way that I have found and works great for me is as follows:
Create an interface inside your "RecycleAdapter" Class (Subclass)
public interface ClickCallback {
void onItemClick(int position);
}
Add a variable of the interface as a parameter in the Constructor.
private String[] items;
private ClickCallback callback;
public RecyclerAdapter(String[] items, ClickCallback clickCallback) {
this.items = items;
this.callback = clickCallback;
}
Set a Click listener in the ViewHolder (another subclass) and pass the 'position' to through the interface
AwesomeViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
callback.onItemClick(getAdapterPosition());
}
});
mTextView = (TextView) itemView.findViewById(R.id.mTextView);
}
Now, when initializing the recycler adapter in an activity/fragment, just Create a new 'ClickCallback' (interface)
String[] values = {"Hello","World"};
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(values, new RecyclerAdapter.ClickCallback() {
#Override
public void onItemClick(int position) {
// Do anything with the item position
}
});
That's it for me. :)
I solved this way
class MyOnClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
int itemPosition = mRecyclerView.getChildAdapterPosition(v);
myResult = results.get(itemPosition);
}
}
And in the adapter
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_wifi, parent, false);
v.setOnClickListener(new MyOnClickListener());
ViewHolder vh = new ViewHolder(v);
return vh;
}
1. Create class Name RecyclerTouchListener.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener
{
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final 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) {
}
public interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
}
2. Call RecyclerTouchListener
recycleView.addOnItemTouchListener(new RecyclerTouchListener(this, recycleView,
new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
Toast.makeText(MainActivity.this,Integer.toString(position),Toast.LENGTH_SHORT).show();
}
#Override
public void onLongClick(View view, int position) {
}
}));
onBindViewHolder() is called for each and every item and setting the click listener inside onBindVieHolder() is an unnecessary option to repeat when you can call it once in your ViewHolder constructor.
public class MyViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener{
public final TextView textView;
public MyViewHolder(View view){
textView = (TextView) view.findViewById(R.id.text_view);
view.setOnClickListener(this);
// getAdapterPosition() retrieves the position here.
}
#Override
public void onClick(View v){
// Clicked on item
Toast.makeText(mContext, "Clicked on position: " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
}
I think the most correct way to get item position is
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override public void onClick(View v) {
View view = v;
View parent = (View) v.getParent();
while (!(parent instanceof RecyclerView)){
view=parent;
parent = (View) parent.getParent();
}
int position = recyclerView.getChildAdapterPosition(view);
}
Because view, you click not always the root view of your row layout. If view is not a root one (e.g buttons), you will get Class cast exception. Thus at first we need to find the view, which is the a dirrect child of you reciclerview. Then, find position using recyclerView.getChildAdapterPosition(view);
No need to have your ViewHolder implementing View.OnClickListener. You can get directly the clicked position by setting a click listener in the method onCreateViewHolder of RecyclerView.Adapter here is a sample of code :
public class ItemListAdapterRecycler extends RecyclerView.Adapter<ItemViewHolder>
{
private final List<Item> items;
public ItemListAdapterRecycler(List<Item> items)
{
this.items = items;
}
#Override
public ItemViewHolder onCreateViewHolder(final ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
view.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
int currentPosition = getClickedPosition(view);
Log.d("DEBUG", "" + currentPosition);
}
});
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(ItemViewHolder itemViewHolder, int position)
{
...
}
#Override
public int getItemCount()
{
return items.size();
}
private int getClickedPosition(View clickedView)
{
RecyclerView recyclerView = (RecyclerView) clickedView.getParent();
ItemViewHolder currentViewHolder = (ItemViewHolder) recyclerView.getChildViewHolder(clickedView);
return currentViewHolder.getAdapterPosition();
}
}
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
}
Simple as that, on ViewHolder
When using data binding and you need to know a RecyclerView click position from inside of an item's click listener:
Kotlin
val recyclerView = view.parent as RecyclerView
val position = recyclerView.getChildAdapterPosition(view)

Categories

Resources