【问题标题】:Why items change order upon scrolling in Android GridView?为什么项目在 Android GridView 中滚动时会更改顺序?
【发布时间】:2012-05-20 09:27:25
【问题描述】:

我在 android 中有一个 GridView,我用从 xml 资源检索到的数据填充它。
例如,我在 GridView 中有 15 个项目按顺序放置。总高度超过了屏幕高度,所以我必须滚动才能看到其余的项目。
问题是当我向上滚动时,不可见行的顺序已经改变。这是一种神秘的行为,因为有时项目会相互交换行。 这是我的getView 方法:

public class ImageAdapter extends BaseAdapter {
        public ImageAdapter(Context c, NodeList cuu) {
                cu = cuu;
        }
        public int getCount() {
                Log.d("Node Count",cu.getLength()+"");
                return cu.getLength();
        }
        public Object getItem(int position) {
                return position;
        }
        public long getItemId(int position) {
                return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
                View myView = convertView;
                if (convertView == null) {
                    Node nd = cu.item(position);
                    Log.d("nodes","Pos: "+(position)+" Name: "+nd.getNodeName()+" Title: "+nd.getAttributes().getNamedItem("title").getTextContent());
                    int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id").getTextContent());
                    LayoutInflater li = getLayoutInflater();
                    myView = li.inflate(R.layout.grid_item, null);
                   ImageView imageView = (ImageView) myView.findViewById(R.id.grid_item_image);
                   myView.setLayoutParams(new GridView.LayoutParams(70, 100));
                   id.download(nd.getAttributes().getNamedItem("icon").getTextContent(),imageView);
                   TextView textView = (TextView) myView.findViewById(R.id.grid_item_text);
                   textView.setText(nd.getAttributes().getNamedItem("title").getTextContent());
                   myView.setTag((Object) catID);
                }else{
                    //Log.d("nodes","Pos: "+(position));
                }
                return myView;
        }
        private NodeList cu = null;
    }

更新:嗯,这很奇怪。经过更多调试后,我注意到在 GridView 中,适配器跳过了第 13 个位置,这意味着它返回 1 而不是 13,然后移动到 14! (我猜 13 是不吉利的!)

【问题讨论】:

  • Adapter 不会自行跳过位置。发布适配器的完整代码。
  • 好的,我把整个 Adapter 放在那里了。

标签: android android-gridview


【解决方案1】:
public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    if (convertView == null) {
        view= inflate your xml
    } else {
        view=convertView;
    }
    // all remaining code like 
    // view.findViewById(R.id.btn).setText("MyButton");                            
    // must be outside if-else
}

【讨论】:

    【解决方案2】:

    如果这是您在 getView 方法中拥有的所有代码,那么您没有正确实现它:

    public View getView(int position, View convertView, ViewGroup parent) {
            View myView = convertView;
            if (myView == null) {           
                Node nd = cu.item(position);
                int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id")
                        .getTextContent());
                LayoutInflater li = getLayoutInflater();
                myView = li.inflate(R.layout.grid_item, null);
                myView.setLayoutParams(new GridView.LayoutParams(70, 100));         
                myView.setTag((Object) catID);
            } 
            Node nd = cu.item(position);
            Log.d("nodes", "Pos: " + (position) + " Name: " + nd.getNodeName()
                    + " Title: "
                    + nd.getAttributes().getNamedItem("title").getTextContent());
            ImageView imageView = (ImageView) myView
                    .findViewById(R.id.grid_item_image);
            id.download(nd.getAttributes().getNamedItem("icon")
                    .getTextContent(), imageView);
            TextView textView = (TextView) myView
                    .findViewById(R.id.grid_item_text);
            textView.setText(nd.getAttributes().getNamedItem("title")
                    .getTextContent());
            return myView;
        }
    

    我不知道上面的代码是否有效,你的有点奇怪。无论如何,我认为您看到的行为是正常的,因为您在适配器中所做的只是填充第一个可见元素,然后当您上下滚动时,适配器将重用 exact 相同的元素,因为回收。在getView 你应该:

    • 检查convertView 是否为null
      • 如果是null,是时候为这个GridView 的元素膨胀一个新的View。您还可以使用持有者模式缓存寻找组成 Views(而不是每次都使用 findViewById 搜索)(您使用 setTag 元素作为膨胀视图,但它是来自 Node 数据的一条数据元素?!?你打算用它做什么?!?)
      • 如果不是null,你什么都不做(或者如果你实现了持有人模式,你会得到带有已经搜索过的Views的标签)

    这就是你应该在 if/else 语句中做的事情

    • 在上面的部分之后,您将使用数据填充Views(因此它们保存了该位置的适当数据)。

    【讨论】:

    • 谢谢,这是因为我对 Android 编程完全陌生。在你的帮助下,我可以让它发挥作用。
    • 泰!你救了我一天
    【解决方案3】:

    我刚刚删除了

    if(convertView==null)
    

    有效

    【讨论】:

      【解决方案4】:

      您的适配器实现存在致命缺陷。

      getView() 中,如果convertViewnull,则扩展布局并填充其小部件。这很好。

      getView() 中,如果convertView 不是null,那么你什么也不做。这是非常错误的。

      如果convertView 不是null,您应该getView() 中执行的操作仍在填充单元格的小部件convertView 表示要回收的单元格,因此您可以跳过通货膨胀并节省 CPU 时间,但您仍然必须更新该单元格的小部件以反映您应该在此特定 getView() 调用中设置的任何位置。

      【讨论】:

      • 我遇到了同样的问题,但我应用了 ViewHolder,但我的图像顺序仍在改变。
      • @CommonsWare 是否包括findViewById() 在内的所有操作都必须在if/else 之外完成?有人说这里和这个信息对我来说是新的。
      • @sandalone:每次调用getView(),您都需要配置行。您使用的if/else 构造(如果有的话)取决于您,只要在调用getView() 时完全配置行。对于 OP,如果 convertView 不是 null,则 OP配置行。
      【解决方案5】:

      如果您的网格项目有多个视图,您可以使用getTag()setTag() 方法。在这种情况下,网格项在滚动时不会再改变它们的位置,性能仍然很好:

      public class SomeAdapter extends BaseAdapter {
      
          public static class ViewHolder {
              public TextView tvTitle;
              public ImageView imgPoster;
          }
      
          //...
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
      
              ViewHolder grid;
              LayoutInflater inflator = activity.getLayoutInflater();
      
              if (convertView == null) {
                  grid = new ViewHolder();
                  convertView = inflator.inflate(R.layout.grid_item, null);
                  grid.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
                  grid.imgPoster = (ImageView) convertView.findViewById(R.id.img_poster);
      
                  convertView.setTag(grid);   // <<-- H E R E
              } else {
                  grid = (ViewHolder) convertView.getTag();   // <<-- H E R E
              }
              grid.tvTitle.setText(dataItem.getTitle());
              grid.imgPoster.setImage(dataItem.getImage());
              return convertView;
          }
      }
      

      【讨论】:

        【解决方案6】:

        我使用了这个解决方案,基于另一个样本,并且工作:

        public View getView(int position, View convertView, ViewGroup parent) {
            View view = null;
            if (convertView == null) {
                view = inflate your xml and apply the View Holder pattern
            } else {
                view = convertView;
            }
            // retrieve the object by Holder pattern 
            // extra code here
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多