Android 在不重新填充的情况下更新GridView/ListView

Android 在不重新填充的情况下更新GridView/ListView,android,android-listview,android-gridview,android-adapter,Android,Android Listview,Android Gridview,Android Adapter,每当更新GridView/ListView时,您都会在适配器上调用notifyDatasetChanged,该适配器会使用新数据重新填充列表,删除列表中当前的所有内容 现在以L预览版设计指南中的这个小例子为例 当适配器重新加载时,您看到的唯一变化是新项目进入时没有任何“闪烁”,或者这是现在只能在L中完成的事情时,是否有可能实现相同的效果 添加新注释时,也可以在googlekeep应用程序中找到这种效果在不重新填充的情况下更新GridView/ListView 如果在每次更新和删除时间时都使用相同

每当更新GridView/ListView时,您都会在适配器上调用
notifyDatasetChanged
,该适配器会使用新数据重新填充列表,删除列表中当前的所有内容

现在以
L预览版
设计指南中的这个小例子为例

当适配器重新加载时,您看到的唯一变化是新项目进入时没有任何“闪烁”,或者这是现在只能在L中完成的事情时,是否有可能实现相同的效果


添加新注释时,也可以在
googlekeep
应用程序中找到这种效果在不重新填充的情况下更新GridView/ListView

如果在每次更新和删除时间时都使用相同的数组列表,而不创建新的ArrayList,则adapter.notifyDatasetChanged()方法可以工作。
请您每次都使用相同的arrayList,不要创建适配器类的新实例,恐怕这都是视觉上的诡计,也就是动画

…删除列表中当前的所有内容。

事实上,没有

notifyDataSetChanged
仅告知基础观察者数据已更改。就这样。作为响应,
getView(…)
将为每个可见视图调用,即可通过
ListView\getChildCount()
访问的编号。由于索引已更改(添加/删除项),或者这些索引中的对象中保存的数据已(^)更改(一个或多个项已更改),因此通过后续调用
ListView#getView(…)
可以直观地刷新数据

“Android开发者”有一段有趣的视频,解释了如何产生你想要的效果:

视频/示例仅讨论单个项目的插入。但它应该可以扩展到所有的数据操作,并具备一定的时间和数学技能

我能够扩展示例代码以插入多个项。我将动画更改为更简单的alpha淡入。单击
添加行
按钮将项目的随机数(介于1和3之间)添加到列表视图中。下面是它的外观:

Psuedo工作流:

  • 在将新项传递给适配器之前,在listview中循环所有可见项,并保存它们的边界(在
    Rect
    中)和快照(在
    BitmapDrawables
    中)

  • 将项目传递给适配器

  • 向ListView的ViewTreeObserver添加一个
    OnPreDrawListener

  • 调用
    onPreDraw(…)
    时,新项目已准备好绘制。我们可以使用带有相应索引的
    ListView#getChildAt(…)
    访问他们的
    视图

  • 所有新项目都设置为“不可见”,并指定alpha动画师

  • 所有旧项目都被指定为平移动画

  • 由于添加新项目,无法通过
    getChildAt(..)
    访问的项目将被指定为翻译动画制作者,以使其离开屏幕(或超出listview范围)

  • 翻译动画师被解雇了。当这些动画师完成运行时,alpha动画师将启动

请注意,动画的类型(alpha、平移、缩放或它们的任意组合)相对来说是不重要的。我想在
GridView
StaggeredGridView
(keep)的情况下,这将更加困难,因为数学将涉及
X
Y
中的翻译。但是工作流应该保持不变


(^)-语法上不正确,但在我看来很自然。

这可以通过抓取视图并更改其中的数据来实现。我举了一个例子,在长时间单击时,您可以在不刷新可见项和不调用notifyDataSetChanged()的情况下更改数据

这个问题在谷歌I/O 2010上被提出,你可以在这里观看:

代码改编自

package com.example.stableids;
导入java.util.ArrayList;
导入java.util.HashMap;
导入java.util.List;
导入android.os.Build;
导入android.os.Bundle;
导入android.annotation.SuppressLint;
导入android.annotation.TargetApi;
导入android.app.Activity;
导入android.content.Context;
导入android.database.DataSetObserver;
导入android.util.Log;
导入android.view.Menu;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.Adapter;
导入android.widget.AdapterView;
导入android.widget.ArrayAdapter;
导入android.widget.ListView;
导入android.widget.TextView;
@TargetApi(构建版本代码蜂窝MR1)
@SuppressLint(“新API”)
公共类MainActivity扩展了活动{
@TargetApi(构建版本代码蜂窝)
@SuppressLint(“新API”)
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
最终ListView ListView=(ListView)findViewById(R.id.ListView);
字符串[]值=新字符串[]{“Android”、“iPhone”、“WindowsMobile”,
“黑莓”、“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”,
“安卓”、“iPhone”、“WindowsMobile”};
最终ArrayList=新ArrayList();
对于(int i=0;ipackage 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;
        }

      }

}