首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更新GridView/ListView而不重新填充

更新GridView/ListView而不重新填充
EN

Stack Overflow用户
提问于 2014-08-19 00:22:32
回答 3查看 2.3K关注 0票数 7

无论何时更新GridView/ListView,都可以在适配器上调用notifyDatasetChanged,该适配器用新的数据重新填充列表,删除当前列表中的所有内容。

现在,以这个小视频为例,来自L Preview设计指南

在你看到的唯一改变是适配器重新加载时没有任何“闪烁”的新条目出现的情况下,是否有可能实现同样的效果?还是这是现在只能在L中完成的事情?

在添加新注释时,也可以在Google Keep应用程序中找到这种效果。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-21 19:54:25

恐怕这都是视觉上的诡计--也就是动画。

...removing当前在列表中的所有内容.

实际上,不是。

notifyDataSetChanged只告诉底层观察者数据已经改变了。就这样。作为响应,为每个可见视图调用getView(...) -- ListView#getChildCount()可访问的数字。由于索引已经更改(添加/删除项),或者保存在这些索引的对象中的数据已更改(^)(一个或多个项已更改),因此数据将通过随后对ListView#getView(...)的调用而可视化地刷新(^)。

“安卓开发者”有一段有趣的视频,解释了你如何产生你想要的效果:DevBytes: ListView细胞插入动画

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

我能够扩展示例代码以插入多个项。我把动画改成了更简单的α淡入。单击Add row按钮会向列表视图中添加一个随机项目数(包括1到3)。如下所示:

Psuedo-工作流:

  • 在将新项传递给适配器之前,循环遍历列表视图中的所有可见项,并保存它们的界限(在Rect中)和快照(在BitmapDrawables中)。
  • 将项传递到适配器
  • OnPreDrawListener添加到ListView的ViewTreeObserver中。
  • 当调用onPreDraw(...)时,将准备绘制新项。我们可以使用带有相应索引的ListView#getChildAt(...)访问它们的ListView#getChildAt(...)
  • 所有新项目都被设置为不可见的,alpha动画器被分配。
  • 所有旧项目都被分配给translation_y动画器
  • 由于添加了新的项目,将不再可以通过getChildAt(..)访问的项目被分配到translation_y动画器中,以使它们脱离屏幕(或超出列表视图界限)。
  • translation_y动画师被解雇。当这些动画师完成运行时,就会启动alpha动画。

请注意,动画的类型(alpha、翻译、缩放或任何这些组合)相对来说是微不足道的。我想,如果是GridViewStaggeredGridView(保存),这将更加困难--这仅仅是因为数学将涉及XY的翻译。不过,工作流应该保持不变。

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

票数 8
EN

Stack Overflow用户

发布于 2014-08-27 09:59:42

这可以通过获取视图并更改其中的数据来实现。我包含了一个示例,在长时间单击时,您可以更改数据,而不需要刷新可见项,也不需要调用notifyDataSetChanged()。

这个问题已经在Google I/O 2010上被问到,你可以在这里观看:

ListView的世界,时间52:30

改编自沃盖拉的代码

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2014-08-21 13:15:57

更新GridView/ListView而不重新填充

如果每次更新和删除时都使用相同的数组列表而不创建新的ArrayList,那么adapter.notifyDatasetChanged()方法就可以工作。请每次都使用相同的arrayList,不要创建适配器类的新实例

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25373971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档