Updating GridView / ListView without refilling

whenever you update the GridView / ListView, you call notifyDatasetChanged on the adapter, which re-populates the list with new data, deleting everything that was currently in the list.

now take this little video for example from the L Preview design guide

is it possible to realize the same effect when the only change that you see is new elements that appear without any β€œflickering” when the adapter reboots, or is it something that can only be done in L right now?

This effect can also be found in the Google Keep app when adding new notes.

+7
android android-listview android-gridview android-adapter
source share
3 answers

I'm afraid that all of his visual tricks are aka animation.

... removing everything on the list.

No, actually.

notifyDataSetChanged tells only the main observers that the data has changed. It. In response to a call, getView(...) is called for each visible view β€” the number available for ListView#getChildCount() . Since either the indexes have changed (adding / deleting elements), or the data stored in objects at these indexes has changed (^) (one or more elements have been changed), the data (^) is visually updated by subsequent calls to ListView#getView(...)

There is an interesting video from Android developers explaining how you can produce the effect that you after: DevBytes: ListView animation insertion animation .

The video / example only talks about inserting one element. But it must be extensible for all operations with data and mathematical skills.

I managed to extend the example code to insert multiple elements. I changed the animation to a simpler alpha effect. Clicking the Add row button adds a random number (from 1 to 3 inclusively) of items to the list. Here's what it looks like:

enter image description here

pseudo-users-technological process:

  • Before transferring new elements to the adapter, view all visible elements in the list and save their borders (in Rect ) and snapshot (in BitmapDrawables )

  • transfer items to adapter

  • add OnPreDrawListener to ListView ViewTreeObserver.

  • when onPreDraw(...) is called, the new elements are ready to draw. We can access their views using ListView#getChildAt(...) with the corresponding indexes.

  • all new elements are set to invisible, and alpha animators are assigned

  • all old elements are assigned animators translation_y

  • elements that will no longer be accessible through getChildAt(..) - due to the addition of new elements - are assigned to translation animators - to get them from the screen (or from the list border)

  • translation_y animators quit. When these animators are already running, alpha animators are launched.

Note that the type of animation (alpha, translation, scale, or any combination of them) is relatively negligible. I believe this will be much more complicated with GridView or StaggeredGridView (keep) - just because the math will include translations in both X and Y The workflow should remain the same.

(^) - grammatically incorrect but natural IMO.

+8
source share

This can be achieved by capturing the view and changing the data there. I included one example where, with a long click, you change the data without updating the visible elements and do not call notifyDataSetChanged ().

This question was asked in Google I / O 2010, you can see it here:

ListView World, 52:30 a.m.

Code adapted from Vogella

 package com.example.stableids; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.os.Build; import android.os.Bundle; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.database.DataSetObserver; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) @SuppressLint("NewApi") public class MainActivity extends Activity { @TargetApi(Build.VERSION_CODES.HONEYCOMB) @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listview = (ListView) findViewById(R.id.listview); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2", "Android", "iPhone", "WindowsMobile" }; final ArrayList<String> list = new ArrayList<String>(); for (int i = 0; i < values.length; ++i) { list.add(values[i]); } final StableArrayAdapter adapter = new StableArrayAdapter(this, android.R.layout.simple_list_item_1, list); listview.setAdapter(adapter); listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @SuppressLint("NewApi") @Override public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) { final String item = (String) parent.getItemAtPosition(position); view.animate().setDuration(2000).alpha(0) .withEndAction(new Runnable() { @Override public void run() { int i = list.indexOf(item); list.remove(item); list.add(i, "MODIFIED"); adapter.mIdMap.put("MODIFIED", position); TextView tv = (TextView)view.findViewById(android.R.id.text1); tv.setText("MODIFIED"); //adapter.notifyDataSetChanged(); view.setAlpha(1); } }); } }); } private class StableArrayAdapter extends ArrayAdapter<String> { HashMap<String, Integer> mIdMap = new HashMap<String, Integer>(); public StableArrayAdapter(Context context, int textViewResourceId, List<String> objects) { super(context, textViewResourceId, objects); for (int i = 0; i < objects.size(); ++i) { mIdMap.put(objects.get(i), i); } } @Override public View getView(int position, View convertView, ViewGroup parent) { Log.d("STABLE ID", "getView called for " + position + " position"); return super.getView(position, convertView, parent); } @Override public long getItemId(int position) { String item = getItem(position); return mIdMap.get(item); } @Override public boolean hasStableIds() { return true; } } } 
+1
source share

Updating GridView / ListView without reuse

If you use the same list of arrays for each update and delete time without creating a new ArrayList, then your adapter.notifyDatasetChanged () method works. Please, you will be the same arrayList every time and do not create a new instance of the adapter class

0
source share

All Articles