I am trying to remove items from a RecyclerView from my adapters onBindViewHolder.
When I call this...
public void removeDropFromView(int position) {
data.remove(position);
notifyItemRemoved(position);
}
...my animation shows, but it will not allow the adapter position to update (the new position 0 becomes position 1).
When I call this...
public void removeDropFromView(int position) {
data.remove(position);
notifyItemRemoved(position);
notifyDataSetChanged();
}
...the item is removed, the position of all my items are updated, but it completely skips the animation.
Some have said my troubles are coming from this not being possible in the onBindViewHolder, but I have tried all of this in the ViewHolder's onClick with the same results.
How can I get the animation to show, while also keeping all of the data in proper order?
Thanks for the help!
Before deleting the data, get its viewholder, then call the setIsRecyclable(false) of the viewholder. Check this, line 102. It uses swipe to delete.
Related
I am trying to change the color of the first row in "monitoredpatientlsit" which is a list view. The change should happen if I click on an item in allpatientslist and it already exists in monitoredpatient. So suppose I click on item 3, which also happens to be item 3 in monitoredpatients. I expect the code to change the color of the first view in monitored patient to red. However it doesn't, and I think it has to something to do with "notifydatasetchanged" method, because when I comment it out, it would work the way I want it to, but when I put it back to the code, there are no changes in the color at all. Any Idea why?
allpatientslist.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (selectedpatients.contains(allpatients.get(position))){
selectedpatients.remove(selectedpatients.indexOf(allpatients.get(position)));
refomatToRed();
monitoredPatientListAdapator.notifyDataSetChanged();
view.setBackgroundColor(Color.parseColor("#F4F6F1"));
}else{
view.setBackgroundColor(Color.parseColor("#B0D880"));
selectedpatients.add(allpatients.get(position));
monitoredPatientListAdapator.notifyDataSetChanged();
}
}
});
public void refomatToRed(){
monitoredpatientslist.getChildAt(0).setBackgroundColor(Color.RED);
}
Edit:
I fixed it by just implementing the change of color inside the adaptor, since every time an item is removed by view due to the scrolling feature, the item is actually destroyed and will lose any formatting down to it.
When you call notifyDataSetChanged() on the adapter, the list is re-drawn. Changing the color of the first child has no effect because this child is destroyed at the following line.
Try inverting the lines like this:
monitoredPatientListAdapator.notifyDataSetChanged();
refomatToRed();
I'am trying to delete a card having in recyclerview. The problem is when i click the delete button in my card the changes does not reflect the next activity. When i click Delete Button the textview and the imageview must change accordingly. But that is not happening.
this is my onclick in viewHolder. I have used Interface. :
public void onClick(View view)
{
//get data from array list
if(view.getId()==R.id.cont_root){
if(itemClickCallback!=null) {
itemClickCallback.onRootClick(getAdapterPosition());
}
}
else{
delete(getAdapterPosition());
}
}
}
This is my delete Method in the adapter :
public void delete( int position){
listData.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount()-1);
}
This is my code when a Cardview is clicked .Card's name is Root.
public void onRootClick(int p) {
//adapter.setItemClickCallback(this);
adapter.notifyItemChanged(p);
ListItem item =(ListItem)listData.get(p);
Intent i = new Intent(this,SecondActivity.class);
Bundle extras=new Bundle();
extras.putString(EXTRA_QUOTE, item.getTitle());
extras.putInt(EXTRA_ATTR,item.getImageResID());
i.putExtra(BUNDLE_EXTRAS,extras);
startActivity(i);
}
Note : i have not used interface method for deleting the element.
Please help. Iam new to Recyclerview. :(
You have to use the Methodes which relate to "what user is seeing" I can call them (Layout side Methods) and they are :
getLayoutPosition()
findViewHolderForLayoutPosition(int)
The first one returns the view position in accordance to the Layout it self and not the adapter
and the second one returns the ViewHolder for the item in the given position of the data set
In your code you are using what i can call (Adapter side Method)
getAdapterPosition()
any changes using The (adapter side Methods) will not be reflected to Layout untill you use (the Layout side Methods)
Hope This helps
Ok so it is a bit complicated, I have a custom RecyclerView Adapter and in the OnBindViewHolder method I would like to remove the current item from the recyclerview depending on some different variables but when I remove the item from the ArrayList and call notifyDataSetChanged(); I get :
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling.
How can I remove the item from the RecyclerView in the onBindViewHolder ? , I do not want to do it before setting the adapter because each item in the recyclerview has a sublist and I want to remove the item if the sublist is empty. Thanks for any ideas and sorry for bad english.
Please follow the method used below as shown in this answer.
private List<DetectedIssue> issues = new ArrayList<DetectedIssue>();
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
issues.remove(position);
notifyItemRemoved(position);
//this line below gives you the animation and also updates the
//list items after the deleted item
notifyItemRangeChanged(position, getItemCount());
} catch (SQLException e) {
e.printStackTrace();
}
}
});
}
#Override
public int getItemCount() {
return issues.size();
}
PS: As can be seen from the documentation it is bad practice to use notifyDataSetChanged() if only an item is added, moved or removed as unnecessary processes are run.
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
If you want the underlying arraylist in some activity be changed then you will have to use an interface to communicate with the activity to change the arraylist.
I know its a bit late (4 years, heh) but I'm in the same solution. As the error states it is actually impossible to call methods such as adapter.notifyItemRemoved(position); or notifyItemRangeChanged(position, getItemCount()); and even the more intensive notifyDataSetChanged(); from within the onBindViewHolder method unless it is within an onClickListener whereby it will be called after the layout is built and not during the build.
A simple workaround for me was to call datalist.remove(position); so if the layout is rebuilt the view is omitted, then simply call holder.itemView.setVisibility(View.GONE);. It's not as clean, but it gets the job done for views you wish to hide.
In the below code 'setlisteners' method is called every time,should'nt value of position change?
There is only one method'setlisteners'in which parameter position is passed,but when in log ,i see that whenever click event happens on my buttons,it shows correct position. should'nt position overwrite itself and show incorrect position because click event can happen at any time ,by that time value of position will have changed?
let's suppose 5 views have been binded and i click on the first
itemview,then should'nt it show me the last position held by the last
binded itemview?
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
setListeners(holder,position);
}
private void setListeners(ViewHolder holder, final int position) {
holder.updownarrow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("ddfg",""+position);
}
});
holder.leftlayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
position will hold the position of the last holder which was bind in onBindViewHolder, since my View does not call onBindViewHolder when i click on it,should'nt position hold the position last binded and show only that one position whenever any view gets clicked?
The position in onBindViewHolder is the same as the position in your adapter/data set. Your Click Listener is being set with the position the individual ViewHolder represented in your data set at the time of binding. Even though the click event isn't being called until after all your Views are binded, each function instance was already set up to use the corresponding position each view was set with.
If each View shared the same instance of a Click Listener, then you would only get the last position. But, each View holds its own instance of a Click Listener.
No, position will hold the position of the last holder which was bin in onBindViewHolder, since your View does not call onBindViewHolder when you click on it.
There are many possibilities to retrieve the correct position - for example if you set & get the position in the Views tag or search for the surrounding ViewHolder and check its position in the adapter or layout.
Dont use the position in onBindViewHolder. use this:
final int adapterPosition = viewholder.getAdapterPosition();
// do what ever with it
You can find my code here:
How to correctly build table with data using onPostExecute and ListView
I need to do loading data from the server when my ListView is scroll to the bottom. I tried to looking for solution on Stackoverflow, but it is not helpful for me.
Also if it's not difficult i like to know how it's work for understand all.
Thank's to all
You have 2 solutions:
1) With OnScrollListener
You must have a class that extends ListView and implements OnScrollListener.
When you initialise the view, set it as the scroll listener :
setOnScrollListener(this);
Implement the method onScroll. It's called when you scroll with the arguments firstVisibleItem, visibleItemCount and totalItemCount.
When firstVisibleItem+visibleItemCount==totalItemCount you reached the bottom of the list, you can call your AsyncTask again to load the next items.
2) With a custom adapter
In the method getView that you must overwrite, you have access to the position of the item being rendered, i.e. about to be visible on the screen.
Let's say you store your items in a List items you know when you reached the bottom of the list when position == items.size()-1. You can then call your AsyncTask.
Warning
Be careful with these 2 solutions, if all the items of the list fit in the screen, your AsyncTask may be called very often and for no reason. You must do the necessary checks for that before starting it.
Use the Scroll state change listener in your program...I hope It will help you definitely ....
listStudies.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (Logic Condition) {
//Here also You can do your Logic here and then you can achieve your wishes.....
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (Logic Condition) {
//You just do your Logic here and then you can achieve your wishes.....
}
}
});