I have a ListView that displays a list of states. Whenever the user selects a state, I will load a list of cities that are in this state. For this, I have a manager that, whenever an item is selected, will replace the underlying list that my custom BaseAdapter reads with the item's children.
The problem is, this works fine, but the items are just replaced on the spot, I'd really want a nice transition for this, that is, the list of states moving to the left and being replaced by the list of cities coming from the other edge
Is there a class or method that could help me animate that? The only option I've thought is to keep two different Listview and fade the first one out while the other one fades in. Not the most elegant solution, I was wondering if this could be achieved somehow with only one ListView
I'm not sure how to do this with ListView, but I know you could use a RecyclerView and add animations in the adapter's onBindViewHolder method.
This method is called once for every visible item when you call notifyDataSetChanged().
Edit:
Something like this:
Some Class:
RecyclerView recyclerv;
MyAdapter mAdapter;
LinearLayoutManager mLayoutManager;
List<String> mDataset;
//instantiate recyclerview, adapter, layoutmanager, dataset. populate dataset.
recyclerv.setDataset(mDataset);
MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> dataset;
public MyAdapter(){}
//extend ViewHolder class here
public class ViewHolder extends RecyclerView.Holder { ... }
//implement onCreateViewHolder
/*implement onBindViewHolder.
*animate your view here, but be sure to add an animation count
else the items will keep getting animated everytime a new item appears */
//implement getItemCount
public void setDataset(List<String> dataset) {
this.dataset = dataset;
notifyDataSetChanged(); //this will trigger onBindViewHolder for every visible item
}
}
Related
I've a vertical RecyclerView and each element of it, is a nested horizontal RecyclerView. Both have their Adapter and ViewHolder. When I change a flag, I want to be able to refresh the drawing of all items in each inner horizontal RecyclerView. I've written a method in the outer adapter that consequently call the inner one:
OuterAdapter:
public void setEditEnabled(boolean enabled) {
innerAdapter.setEditEnabled(enabled);
notifyDataSetChanged();
}
InnerAdapter:
public void setEditEnabled(boolean enabled) {
this.editable = enabled;
notifyDataSetChanged();
}
Then in the activity I call:
outerAdapter.setEditEnabled(editable);
outerRecyclerView.invalidate();
But only some "rows" are correctly updated...How can I solve this?
EDIT: so the flow is:
Outer setEditEnabled -> inner setEditEnabled -> inner notify -> outer notify
First of all, why are you calling invalidate on the RecyclerView. when you call notifyDataSetChanged() on the adapter, it automatically updates the RecyclerView items. And why is there only one inner Adapter. I think there should be a different adapter for each horizontal RecyclerView.
I don't know if I'm doing it right, but it seems to work fine.
Previously I was instantiating a new innerAdapter in the ViewHolder constructor:
class ViewHolder extends RecyclerView.ViewHolder {
RecyclerView innerRecyclerView;
ViewHolder(View view) {
super(view);
[...] // init things
innerRecyclerView.setAdapter(new InnerAdapter(context, onItemClickListener));
}
}
Now I'm doing the new in the OuterAdapter constructor and saving the reference as private field of the class:
public DailyMenusAdapter(Context context, OnItemClickListener onItemClickListener) {
innerAdapter = new InnerAdapter(context, onItemClickListener);
}
Then I pass the reference to:
innerRecyclerView.setAdapter(innerAdapter);
Is that ok in your opinion? So reusing the same adapter over and over again.
You know, I think if you will create annonimous Adapter class instead of notifyDataSetChanged (somethink like mRecyclerView.setAdapter(new YourAdapter(this, listOfDataYouPass))) it will work fine.
EDIT:Usually we do something like this to set adapter to RecyclerView:
List mLogs = new ArrayList<>;
mLogs.addAll (logs);
mLogAdapter = new LogAdapter(this, mLogs);
mRecyclerView = findViewById(R.id.log_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mLogAdapter);
and then, when we need to modify something we call mLogAdapter.notifyDataSetChanged. Or just call notifyDataSetChanged inside Adapter class. But in many cases it works wrong, hard to say why in your case.
So here is what I advise:
instead of call notifyDataSetChanged make this method and call it when you need to update or change something:
private void updateRecyclerView (){
mRecyclerView.setAdapter(new LogAdapter(this, mLogs));
}
Note: Do not pay attention to the names, I took code from the first project I got
I know there are lots of threads already on this topic, but none of the given solutions worked for me so far. I'm trying to add or update an item of a RecyclerView. Here's my code so far:
MainActivity
private MyListItemAdapter mAdapter;
private RecyclerView recyclerView;
// called on activity create
private void init() {
// initialize activity, load items, etc ...
mAdapter = new MyListItemAdapter(this, items);
recyclerView.setAdapter(mAdapter);
}
// called when I want to replace an item
private void updateItem(final Item newItem, final int pos) {
mAdapter.replaceItem(newItem, pos);
}
MyListItemAdapter
public class MyListItemAdapter extends RecyclerView.Adapter<MyListItemAdapter.MyListItemViewHolder> {
private List<Item> mItems;
public void replaceItem(final Item newItem, final int pos) {
mItems.remove(position);
mItems.add(position, newItem);
notifyItemChanged(position);
notifyDataSetChanged();
}
}
I tried to make this changes from the MainActivity aswell, but in every case I tried my list doesn't get updated. The only way it worked was when I reset the adapter to the recyclerView:
mAdapter.notifyDataSetChanged();
recyclerView.setAdapter(mAdapter);
which obviously is a bad idea. (aside from the bad side effects wouldn't even work when I'm using lazy loading on my lists).
So my question is, how can I make notifyDataSetChanged() work properly?
edit
I found a solution for replacing items. After mAdapter.replaceItem(newItem, pos); I had to call recyclerView.removeViewAt(position);
This works for replacing an item, but doesn't solve my problem when I want to add items (e.g. lazy loading) to my list
edit2
I found a working solution for adding items
Adapter:
public void addItem(final Item newItem) {
mItems.add(newItem);
notifyDataSetChanged();
}
Activity:
private void addItem(final Item newItem) {
mAdapter.addItem(newItem);
recyclerView.removeViewAt(0); // without this line nothing happens
}
For some reason this works (also: it doesn't remove the view at position 0), but I'm sure this isn't the correct way to add items to a recyclerView
This should work:
private ArrayList<Item> mItems;
public void replaceItem(final Item newItem, final int position) {
mItems.set(position, newItem);
notifyItemChanged(position);
}
ArrayList.set() is the way to go to replace items.
For adding items, just append them to mItems and then go notifyDatasetChanged(). Another way to go is to use notifyItemRangeInserted(). Depending on where/how are you adding new items and how many of them, it might be worth it.
Use
mItems.set(position, newItem);
instead of
mItems.add(position, newItem);
because .set method will replace your data to particular position.
I have implemented my RecyclerView and even added an onscrolllistener to support infinity scrolling and now I'm stuck with a, hopefully, easy problem: How can I add the newly loaded data to the existing dataset?
My current approach: I create a new array with the length of the existing dataset + the length of the newly loaded data. I System.arraycopy my existing dataset and add the new content with a for-loop.
This works but the list is always reset (scrolls back to the top) and I assume my way to add additional content is overly complicated/wrong, though the tutorials I have looked at seem to pass over this "detail".
Update: I'm currently calling "scrollToPosition" on the UI-Thead after the data has been loaded, but I doubt this is the correct way of doing this or am I wrong?
You shouldn't be adding stuff to your dataset, you will sooner or later run out of memory. What you can do is return a big number (I used Short.MAX_VALUE) item in getItemCount inside your adapter and in the method that requests a view for postion you should do position % list.size();
It is not a truly endless RecyclerView this way, but good enough. I will paste some code tomorrow, I don't have it here now :/
I think you have to add items inside your adapter. Let`s say
class Adapter extends Recycler.Adapter<Recycler.ViewHolder>{
List<YourCustomObject> list;
public Adapter(){
list = new ArrayList<>();
}
public void addItem(YourCustomObject item){
list.add(item);
notifyItemDateSetChanged(); //This method for adapter to notice that list size have been changed
}
// Here your views
}
There is implementation of Your fragment or Activity where you retrieve data from internet.Let` say
class MainActivity extends AppCompactActivity{
Adapter adapter = new Adapter();
List<YourCustomObjects> objects;
public void onCreateView(){
//////// Something yours
}
public void onLoadMore(){
///// Your operation to retrieve data and init it to your list objects
for(YourCustomObject object : objects){
adapter.addItem(object);
}
}
}
Hi friends i have a listview and the contents are fetched from a webservice call. In that webservice call, there are fields like
"OGType": "ORG" and "OGType": "GROUP"
If click a button, the listview must shows the item having "OGType": "ORG", and hide the item having "OGType": "GROUP". Hope you understand what i meant. Please anyone help me for that. Thanks in Advance.
Try to set new data (only with ORG) to adapter and then call
adapter.notifyDataSetChanged();
You can do it in your getView Method in your Adapter Class. That's the header
public View getView(int pos, View convertView, ViewGroup, parent)
There you can properly hide the element(s) you want, you know, using the method setVisibility()
For more help you can take a look here
You can create a custom adapter and pass data to it in the form of Array or ArrayList (ArrayList is better when dealing with Custom Adapters). Whenever you need to add or remove the data from ListView, just add or remove the item to or from you ArrayList and call notifyDataSetChanged() on your custom adapter and it will update the ListView automatically.
In your case, whenever you click a button, edit you ArrayList and call your custom adapter's method called notifyDataSetChanged() and that's it. You'll see every time you call this method ListView will refresh itself if you have made any changes to the data. Hope it helps.
NOTE - CUSTOM ADAPTER IS NOT COMPULSORY. ANY ADAPTER CAN BE USED e.g SimpleAdapter, ArrayAdapter etc.
You can use a visible list and filters lists. You should use "visible" for complete the BaseAdpter as always, then, you can change the pointer of visible to other list (all, filter...)
Don't worry by the memory, are pointers, you only have each element only once.
public class MyAdapter extends BaseAdapter {
private ArrayList<MyItem> visible;
private ArrayList<MyItem> all;
private ArrayList<MyItem> filter;
public MyAdapter(ArrayList<MyItem> items) {
all = items;
visible = all; //Set all as visible
filter = new ArrayList<Item>();
for (Item i : items)
if (i.getType().equals("ORG"))
filter.add(i);
}
//Complete adapter using "visible"
public void showOnlyOrg() {
visible = filter;
notifydatasetchanged();
}
}
The non hackish way will be to remove the items from your Collection which you use to generate the listview and then call notifyDataSetChanged();
I'm working on refreshing a list in Android but can't seem to get it right.
I've used notifyDataSetChanged(); at every point that I thought applicable (currently using dialogs for input), but it doesn't work, and I've got to the point of plastering it around all over the place and it still won't refresh.
Am I right in saying this should refresh the list while your looking at it, or it will rebuild the list and you still have to refresh the view?
If anyone has got any suggestions for the positioning of it in relation to constructing a list I'd be glad to hear.
Is this a ListActivity? I have a ListActivity in my project at the moment and I have my own adapter class within it that extends ArrayAdapter.
My experience is that calling notifyDataSetChanged() on my extended list adapter class instance does immediately cause a refresh of the list View being displayed. So, as soon as I call .notifyDataSetChanged() on my adapter instance, the list View is regenerated which therefore causes my adapter's implementation of getView() to be called to generate each individual row view again. So, the user selects a context menu item which triggers some change to the data and then a call to .notifyDataSetChanged(), and the screen instantly refreshes with the new data.
So to add some code snippets to be clear:
I have a ListActivity
public class VarListActivity extends ListActivity {
Within it, I extend ArrayAdapter
class VarAdapter extends ArrayAdapter{
...
#Override
public View getView(int position, View convertView, ViewGroup parent){
// Creates the views based upon myData
...
#Override
public int getCount(){
...
And I create an instance of that array adapter
la = new VarAdapter(this, R.layout.row0);
And when a context menu item is selected
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.a_context_menu_option:
// Does a call to perform modifications to myData
la.notifyDataSetChanged();
return true;
I'm just chucking this all down just in case it's of any similarity to your situation, but really we need to know a bit more about your code.