如何避免列表视图中的图像闪烁

时间:2016-03-15 14:10:46

标签: android image android-imageview universal-image-loader

我有一个显示一堆图像的listivew。我正在使用通用图片加载器将此图像从文件加载到图像视图。

此图像具有不同的尺寸,我希望它们在每个图像宽高比方面具有相同的宽度但不同的高度。

为实现这一目标,我尝试将以下内容设置为我的imageview

<ImageView
   android:layout_width = "400dp"
   android:layout_height="wrap_content"
   android:scaleType="centerCrop"
   android:adjustViewBounds="true"/>

这种方法的问题是当滚动列表视图时会有很多闪烁,因为事先不知道imageview高度,并且必须首先使用我的宽度缩放图像来计算每个图像高度相对于它的宽高比

如何提前计算每个图像高度而不是让imageview处理它?<​​/ p>

如果我的图像是400 X 700,并且我希望图像视图宽300像素,我如何使用图像尺寸计算图像视图的高度并保持图像宽高比?这可以帮助避免在滚动列表视图时闪烁。

5 个答案:

答案 0 :(得分:3)

这种闪烁的原因是,在列表视图中列表项被重用。重新使用时,列表项中的图像视图将保留首先显示的旧图像参考。稍后,一旦下载了新图像,它就会开始显示。这会导致闪烁行为。 为避免此闪烁问题,请务必在重新使用时清除imageview中的旧图像引用。

在您的情况下,在 holder =(ViewHolder)convertView.getTag();

之后添加 holder.image.setImageBitmap(null);

因此,您的getView()方法将如下所示:

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

    ...

    if (convertView == null) {
        LayoutInflater inflater = getLayoutInflater();
        convertView = inflater.inflate(viewResourceId, null);

        holder = new ViewHolder(convertView);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
        holder.image.setImageBitmap(null)
    }

    ...

    return convertView;
}

答案 1 :(得分:1)

经过数小时的研究,我能够知道在保持图像宽高比的同时计算新的图像视图高度的方法。

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

//Returns null, sizes are in the options variable
BitmapFactory.decodeFile("/sdcard/image.png", options);
int width = options.outWidth;
int height = options.outHeight;

//calculating image aspect ratio
float ratio =(float) height/(float) width;

//calculating my image height since i want it to be 360px wide
int newHeight = Math.round(ratio*360);

//setting the new dimentions
 imageview.getLayoutParams().width = 360;
 imageview.getLayoutParams().height = newHeight;

 //i'm using universal image loader to display image
 imaheview.post(new Runnable(){
  ImageLoader.getInstance().displayImage(imageuri,imageview,displayoptions);
 });

答案 2 :(得分:0)

您可以这样做:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

//Returns null, sizes are in the options variable
BitmapFactory.decodeFile("/sdcard/image.png", options);
int width = options.outWidth;
int height = options.outHeight;
//If you want, the MIME type will also be decoded (if possible)
String type = options.outMimeType;

答案 3 :(得分:0)

我如何解决它是通过创建一个Bitmap[]数组变量来存储图像,然后在适配器的getView()中,我使用位置检查Bitmap[]数组中的图像是否为{{1}或者有价值。如果它有值,那么我使用该值而不是再次调用null构造。

例如:

<强> YourCustomArrayAdapter.java

new DownloadImageTask()

然后,在下载图像后,在图像下载器构造中,插入该位置的public class MyCustomArrayAdapter extends ArrayAdapter { private static Bitmap[] myListViewImageViewsArray = new Bitmap[listViewItemsArray.length]; private String[] myListViewImageURLsArray = new String[listViewItemsArray.length]{ "image_url_1", "image_url_2", ... ... }; @Override public View getView(int position, View view, ViewGroup parent){ CustomViewHolder vHolder; if(view == null){ view = inflater.inflate(R.layout.movies_coming_soon_content_template, null, true); vHolder = new CustomViewHolder(); vHolder.imageView = (AppCompatImageView) view.findViewById(R.id.my_cutom_image); vHolder.imageUrl = ""; view.setTag(vHolder); } else{ vHolder = (CustomViewHolder)view.getTag(); // -- Set imageview src to null or some predefined placeholder (this is not really necessary but it might help just to flush any conflicting data hanging around) vHolder.imageView.setImageResource(null); } // ... // -- THIS IS THE MAIN PART THAT STOPPED THE FLICKERING FOR ME if(myListViewImageViewsArray[position] != null){ vHolder.imageView.setImageBitmap(myListViewImageViewsArray[position]); }else{ new DownloadImageTask(position, vHolder.imageView).execute(vHolder.imageUrl); } // -- END OF THE FLICKERING CONTROL } } 图像阵列。例如:

<强> YourImageDownloaderClass.java

Bitmap[]

答案 4 :(得分:0)

我的建议是使用网格视图来避免第一次加载的图像闪烁,如果它是相同的网址,它将从缓存加载

 Glide.with(mContext)
            .load(item.getImageUrl())
            .into(holder.mIVGridPic);