Android上的GridView滚动问题

时间:2011-03-20 15:05:23

标签: android gridview

这一定非常简单,我忽略了,但我有以下问题(帖子相当冗长,但我想提供尽可能多的信息:))。

我的Android应用程序中有一个gridview,每个单元格都有自定义视图:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
    <GridView
    android:id = "@+id/photosGridView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:clickable="true" 
    android:drawSelectorOnTop="true" 
    android:focusable="true" 
    android:focusableInTouchMode="true" 
    android:numColumns="6" 
    android:columnWidth="90dp"
    android:verticalSpacing="5dp"
    android:horizontalSpacing="5dp"
    android:stretchMode="columnWidth"     
    >
</GridView>

</RelativeLayout>

并且每个单元格都是

<?xml version="1.0" encoding="utf-8"?>
<com.myapp.widgets.ImageThumbView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background = "@android:color/transparent"
  android:paddingLeft = "1dip"
  android:paddingRight = "1dip"
  android:paddingTop = "2dip"
  android:paddingBottom = "2dip"
  >
<ImageView
    android:id="@+id/thumbImage"
    android:layout_width="fill_parent"
    android:layout_height = "fill_parent"
    android:src="@drawable/icon_small"
    /> 

  <RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height = "fill_parent"
    android:background = "@android:color/transparent"
   >

  <ImageView
   android:id="@+id/iconRight"
   android:layout_width="40px"
   android:layout_height = "40px"  
   android:src="@drawable/album_check"
   android:visibility="gone"
   android:layout_alignParentTop = "true"
   android:layout_alignParentRight = "true"     
   />

  <ImageView
   android:id="@+id/iconLeft"
   android:src="@drawable/album_check"
   android:visibility="gone"
   android:layout_width = "40px"
   android:layout_height="40px"
   android:layout_alignParentTop = "true"
   android:layout_alignParentLeft = "true"     
   /> 
</RelativeLayout>

</com.myapp.widgets.ImageThumbView>

我的适配器看起来像这样:

public class ImageAdapter extends BaseAdapter {
    private List<String> mPictures = null;

    public ImageAdapter(List<String> pictures) {
         mPictures = pictures;
    }

    public int getCount() {
          return mPictures != null ? mPictures.size() : 0;
    }
    public Object getItem(int position) {
          return mPictures != null ?  mPictures.get(position) : null;
    }
    public long getItemId(int position) {
          return mPictures != null ? position : -1;
    }
    @Override
    public View getView(int position,View convertView,ViewGroup parent) 
    {
        ImageThumbView i = null;
        try
            {               
            Thread.sleep(100);

            if (convertView == null) 
            {
                String path = mPictures.get(position);
                Log.d(((Integer)position).toString(), path);
                i = addSingleView(_li, path);
                TextView idx = (TextView) i.findViewById(R.id.caption);
                if (idx != null)
                    idx.setText(((Integer)position).toString());
            }
            else 
            {
                Log.d(((Integer)position).toString(), "ALREADY NOT NULL");
                i = (ImageThumbView) convertView;
                                    // These 2 lines were added only in desperate attempt to get it working, but it makes no difference
                String path = mPictures.get(position);
                i.updateView(path);
            }
        }
        catch(InterruptedException ie)
        {
            ie.printStackTrace();
        }
    return i;
        }
}

所以最初它正常工作,即它显示前18个图像和下一行的几个像素。但是当我开始滚动网格时,图像开始随机出现,即在最后一个图像之后,我从头开始看到很少,依此类推。出于好奇,我尝试了几个这样的样本:http://androidsamples.blogspot.com/2009/06/how-to-display-thumbnails-of-images.html ......并看到相同的结果。

那么,我做错了吗?为什么GridView会显示比预期更多的项目?为什么物品出现在错误的位置?

BR, 亚历

4 个答案:

答案 0 :(得分:20)

实际上这里的问题是你在if或else中设置了“convertView”的内容。或者,在实例化视图后,如果它为null,则应始终执行此操作,并仅在返回视图之前设置内容。

因此,您确定视图的内容始终是正确的,使用位置更新,而不是使用错误的回收视图。

因此,您通常应该做以下事项:
(基于Android指南here中的教程)

public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) { 
        imageView = new ImageView(mContext);
        //just creating the view if not already present
    } else {
        imageView = (ImageView) convertView;
        //re-using if already here
    }

    //here is the tricky part : set the content of the view out of the if, else
    //just before returning the view
    imageView.setImageResource(mThumbIds[position]);
    return imageView;
}

答案 1 :(得分:10)

答案是回收视图。

一般来说,你的getView应该总是这样:

public class ImageAdapter extends BaseAdapter {

    private List<String> mUrls; // put your urls here
    private Map<String, Drawable> mImages; // cache your images here

    public ImageAdapter() {
        ...
        mUrls = new ArrayList<String>();
        mImages = new HashMap<String, Drawable>();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder; // Use the ViewHolder pattern for efficiency

        if (convertView == null) {
            // first time this view has been created so inflate our layout
            convertView = View.inflate(this, R.layout.my_grid_item, null);
            holder = new ViewHolder();
            holder.image = convertView.findViewById(R.id.image);
            holder.text = convertView.findViewById(R.id.text);
            convertView.setTag(holder); // set the View holder
        } else {
           holder = (ViewHolder) convertView.getTag();
        }

        // update the current view - this must be done EVERY
        // time getView is called due to view recycling
        holder.text.setText(Integer.toString(position));

        // check our cache for the downloaded image
        final String url = mUrls.get(position);
        if (mImages.get(url) != null)
            holder.image.setImageDrawable(mImages.get(url));
        else
            loadImage(url, holder.image);

        // return our view
        return convertView;
    }

    public loadImage(final String url, final ImageView image) {
        // load an image (maybe do this using an AsyncTask
        // if you're loading from network
    }

    ...
}

您的ViewHolder课程类似于

public class ViewHolder {
    ImageView thumbImage;
    TextView text;
}

然后你不应该遇到任何问题。另外我不确定为什么你需要在你的getView中睡觉?这将减慢GridView的滚动速度。

答案 2 :(得分:3)

使用标准的Lazy Loader来获取图像,但永远不会更新onpostexecute,这会导致图像更新速度过快并获得您不想要的随机性。

我甚至使用了代码:

if (result != null && !mFlinging && myPosition < 12)
{   
   imageView.setImageBitmap(result);
}

int onpostexecute然后会为第一个屏幕正确更新图像,但是如果你扔掉图像屏幕然后再回到第一个屏幕再次获得随机性,那么我现在使用:

mPhotoView.setOnScrollListener(new OnScrollListener() { 



            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                // TODO Auto-generated method stub

            }

            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // TODO Auto-generated method stub
                if(scrollState != SCROLL_STATE_IDLE) {
                  mAdapter.setFlinging(true);
                } else {
                  mAdapter.setFlinging(false);   
                }

                int first = view.getFirstVisiblePosition(); 
                int count = view.getChildCount(); 

                if (scrollState == SCROLL_STATE_IDLE || (first + count > mAdapter.getCount()) ) { 
                    mPhotoView.invalidateViews(); 
                }

            } 
        }); 

更新视图。

答案 3 :(得分:0)

我遇到了同样的问题。 我正朝着在后台渲染视图的方向前进;

我正在研究这些代码,如果有帮助的话:

http://blog.tomgibara.com/post/7665158012/android-adapter-view-rendering

https://github.com/desertjim/LazyLoadingGridView