java - GridView 滚动条 : erratic behaviour when dynamically adding images

标签 java android gridview

我正在尝试制作某种图片库,其中图片在后台加载,并在加载完成后动态添加到 gridView。图片加载效果很好,但如果 gridView 内的图片超过屏幕高度,gridView 的滚动行为将无法按预期工作。

出于测试目的,我加载了 15 张虚拟图像,对齐成两列。加载所有图像后,根据右侧的滚动条,gridView 的高度似乎适合其内容高度(左列中的 8 个图像或行)。但是,如果我尝试滚动超过第 4 行项目以到达 View 底部(第 5/6/7/8 行),则滚动条指示 gridView 的高度已更改并且已到达 View 底部。无法滚动到第 4 行。如果我再次向上滚动,gridView 似乎又包含 8 行。

same gridView with different content size

左 View :gridView 似乎包含 15 张图像。 右 View :gridView突然好像只有8张图片

我已经尝试过使用不同的方法,例如提到的 ExpandableHeightViewGrid here ,但滚动行为是相同的。我会选择在一行中使用多列图像的 gridView(就像使用 listView),因为如果我要加载的图像超过 15 个,滚动到底部会很烦人。

这是我的代码:

photo_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

    <!-- This is basically a HorizontalScrollView where i add some buttons -->
    <com.my.HorizontalButtonScrollList
        android:id="@+id/horizontalButtonScrollList"
        android:layout_width="match_parent"
        android:layout_height="50dip">
    </com.my.HorizontalButtonScrollList>

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <GridView
            android:id="@+id/gridView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:columnWidth="100dp"
            android:numColumns="2"
            android:verticalSpacing="0dp"
            android:horizontalSpacing="0dp"
            android:stretchMode="columnWidth"
            android:gravity="center"
            android:scrollbars="vertical">
        </GridView>

    </android.support.v4.widget.SwipeRefreshLayout>

</LinearLayout>

PhotoGalleryActivity.java (I simplified the code for better readability)

public class PhotoGalleryActivity extends myBaseView {

    private GridView gridView;
    private PhotoGalleryImageAdapter imageAdapter;
    private PhotoGalleryModel[] photoGalleryModels;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.photo_gallery);
        gridView = (GridView) findViewById(R.id.gridView);

        loadImages();
    }

    void loadImages() {

        photoGalleryModels = PhotoGalleryModel.getFakeData();
        imageAdapter = new PhotoGalleryImageAdapter(this, photoGalleryModels);
        gridView.setAdapter(imageAdapter);
    }
}

PhotoGalleryImageAdapter (also simplified)

public class PhotoGalleryImageAdapter extends BaseAdapter {

    private Context mContext;
    private PhotoGalleryModel[] photoGalleryModels;

    public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
        mContext = c;
        photoGalleryModels = models;
    }

    @Override
    public int getCount() { return photoGalleryModels.length; }

    @Override
    public Object getItem(int position) { return null; }

    @Override
    public long getItemId(int position) { return 0; }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        final ImageView imageView = new ImageView(mContext);    
        DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
            @Override
            public void MyHttpCallback_OnSuccess(Object data, String responseString)
            {
                if(data instanceof Bitmap) {
                    imageView.setImageBitmap((Bitmap)data);
                }
            }

            @Override
            public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
            {}
        });

        convertView = imageView;    
        return convertView;
    }
}

如果有人能在这里帮助我并帮助我修复 gridView 以便我可以按预期滚动浏览所有已加载的图像,我将非常高兴。

最佳答案

嗯,看来是我自己忽略了,解决了这个问题。在我跳过修复 gridView 因为我不知道该怎么做之后,我实现了使用 LruCache 缓存图像(如 Android 开发人员的 training page 所示)以节省一些内存。突然之间,gridView 的滚动行为也得到了修复。

这是我的改动:

PhotoGalleryImageAdapter(现在有缓存)

public class PhotoGalleryImageAdapter extends BaseAdapter {

    private Context mContext;
    private PhotoGalleryModel[] photoGalleryModels;
    private LruCache<String, Bitmap> mMemoryCache;

    public PhotoGalleryImageAdapter(Context c, PhotoGalleryModel[] models){
        mContext = c;
        photoGalleryModels = models;

        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
        protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    @Override
    public int getCount() { return photoGalleryModels.length; }

    @Override
    public Object getItem(int position) { return null; }

    @Override
    public long getItemId(int position) { return 0; }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        final ImageView imageView = new ImageView(mContext);
        final String imageKey = photoGalleryModels[position].thumb_image_url;
        final Bitmap bitmapImage = mMemoryCache.get(imageKey);

        if (bitmapImage != null) {
            imageView.setImageBitmap(bitmapImage);
        }
        else {

            DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
                @Override
                public void MyHttpCallback_OnSuccess(Object data, String responseString) {
                    if (data instanceof Bitmap) {
                        mMemoryCache.put(imageKey, (Bitmap)data);
                        imageView.setImageBitmap((Bitmap)data);
                    }
                }

                @Override
                public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
                {}
            });
        }

        convertView = imageView;
        return convertView;
    }

}

我很高兴 gridView 终于可以工作了,但我不高兴的是它在没有缓存图像的情况下对我不起作用。我可能应该在加载图像之前在 imageAdapter 的 getView() 方法中设置 imageView 的边界。我将尝试在不使用缓存的情况下修复 gridView,如果我找到了解决方案,我会更新我的答案,以防有人遇到同样的问题。在那之前,我很高兴我设法让它发挥作用:)

更新:

我终于让它在有缓存和没有缓存的情况下都能工作。这是我更新的 PhotoGalleryImageAdapter:

public View getView(int position, View convertView, ViewGroup parent) {

    final ImageView imageView;
       // set the imagge's bounds if it is not loaded yet
    if (convertView == null) {
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(imageSize, imageSize));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(0, 0, 0, 0);
    }
    else {
        imageView = (ImageView) convertView;
    }

    final String imageKey = photoGalleryModels[position].thumb_image_url;
    final Bitmap bitmapImage = mMemoryCache.get(imageKey);

    if (bitmapImage != null) {
        imageView.setImageBitmap(bitmapImage);
    }
    else {
        imageView.setImageBitmap(emptyBitmap);
        DownloadImageWithURL(photoGalleryModels[position].thumb_image_url, new MyHttpCallback() {
            @Override
            public void MyHttpCallback_OnSuccess(Object data, String responseString) {
                    if (data instanceof Bitmap) {
                    mMemoryCache.put(imageKey, (Bitmap)data);
                    imageView.setImageBitmap((Bitmap)data);
                }
            }

            @Override
            public void MyHttpCallback_OnError(String responseString, ErrorDataModel error)
            {}
        });
    }
    convertView = imageView;
    return convertView;
}

正如预期的那样,我需要在加载图像之前设置图像边界。

因为我将 gridView 的 numColumns 参数更改为“auto_fit”,图像的宽度/高度 (100dp + stretchMode columnWidth) 计算如下:

int imagesPerRow = screenSize.x / (int)(100 * mContext.getResources().getDisplayMetrics().density);
imageSize = screenSize.x / imagesPerRow;

在加载 imageView 的 bitmapImage 之前,我创建了一个空位图图像并将其分配给 imageView(找到代码 here ):

emptyBitmap = Bitmap.createBitmap(imageSize, imageSize, Bitmap.Config.ARGB_8888);

无论是否使用 LruCache,gridView 现在都可以正常工作。我不知道回答自己的问题是否是常见的做法,但我认为这样做可以帮助面临类似问题的其他人。

关于java - GridView 滚动条 : erratic behaviour when dynamically adding images,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35462364/

相关文章:

c# - 在 GridView 中编辑行时如何设置文本框的宽度?

java - 将 nextInt 与数组一起使用(java 开始)

java - 比较 Java 的 lambda 表达式和 Swift 的函数类型

c# - UWP 中的 GridView

android - 无法解析或不是 SUPPORTED_ABIS、FLAVOR & VERSION_CODES.LOLLIPOP 的字段

安卓 OCR : AndrOCR source code error

html - GridView 的CSS

java - 边框布局不起作用?

java - Java移位运算符0十六进制数

java - 通过 Android 应用程序在 Whatsapp 上共享时,显示无标题而不是文件名