如何在View循环后保持ViewHolder的宽度

时间:2015-04-12 09:28:16

标签: android android-layout android-recyclerview recycler-adapter

我正在使用RecyclerView作为水平列表来显示我的图片。

如果我滚动到第五张图片,前两个或三个将被回收,ViewHolder会丢失其宽度。如果我回滚到第一张图像,图像会再次加载,并在滚动时导致跳转。

以下是R.layout.fragment_details_view_img_item

<ImageView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/details_view_img_item"
  android:background="@color/red"
  android:adjustViewBounds="true"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" >
</ImageView>

我的ViewHolder和适配器:

private class ViewHolder extends RecyclerView.ViewHolder {

    ImageView img;

    public ViewHolder(ImageView imgV){
        super(imgV);
        img = imgV;
    }
}

private class ImageListAdapter extends RecyclerView.Adapter<ViewHolder> {

    [...]

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {

        View v = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_details_view_img_item, parent, false);
        v.setOnClickListener(listener);

        logDebug("onCreateViewHolder");

        return new ViewHolder((ImageView) v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {

        logDebug("onBindViewHolder");

        ImageItem item = data.get(i);

        if (item != null) {

            ImageView imgView = viewHolder.img;
            imgView.setTag(item);

            String imgurl = ImageUtil.imgUrlForAvailableHeightInPX(item, parentHeight);

            ImageLoader.instance().loadASYNC(imgurl, imgView);

        }
    }

    @Override
    public void onViewRecycled(ViewHolder holder) {
        super.onViewRecycled(holder);
        logDebug("onViewRecycled: " + holder.img.getTag());
    }

}

那么如何保持ViewHolder的宽度?

1 个答案:

答案 0 :(得分:0)

在我开始解决这个问题之前,有一点需要明确。 ViewHolder没有任何宽度,ImageView它&#34;拥有&#34;确实有宽度,这就是你想要控制的东西。

现在,考虑到这一点,你的问题是(在查看你的代码做出某些假设之后)你需要知道某个图像处于特定高度时的宽度,同时保持纵横比 - 在它到达之前来自服务器。

这是一个棘手的问题。

一种选择是预加载所有图像。然而,这对于内存非常昂贵,并且可能导致内存崩溃。

更好的选择是加载所有图像&#39;细节,没有实际下载图像&#39;像素。然后,您需要记住某些缓存中所有图像的纵横比,并在实际下载图像内容之前设置您要加载的图像的尺寸。

要下载图片的尺寸而不下载图片本身,您应该使用以下内容:

public float getImageAspectRatio(InputStream inputStreamFromServer)
{
    BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
    decodeOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(inputStreamFromServer, null, decodeOptions);

    final float imageDesiredWidth = decodeOptions.outWidth;
    final float imageDesiredHeight = decodeOptions.outHeight;

    return imageDesiredWidth / imageDesiredHeight;
}

使用此方法后,您需要使用此功能预加载所有图像:

private float[] mAspectRatios;
public void decodeAllAspectRatios(List<String> imageUrls)
{
    mAspectRatios = new float[imageUrls.size()];
    InputStream inputStream;
    int index = 0;

    for (String url : imageUrls) 
    {
        // Get the input stream from the image url using whatever method you use.

        mAspectRatios[index] = getImageAspectRatio(inputStream);
        index++;  
    } 
}

重要提示:在此方法完成工作之前,您的RecyclerView不应该开始工作。

预加载所有宽高比后,我们将返回ViewHolder:

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {

        logDebug("onBindViewHolder");

        ImageItem item = data.get(i);

        if (item != null) {

            ImageView imgView = viewHolder.img;

            // set the layout params of the image, making it fit the correct size prior to loading the bitmap.
            imgView.setLayoutParams(new LayoutParams(parentHeight * mAspectRatios[i], parentHeight));
            imgView.setTag(item);

            String imgurl = ImageUtil.imgUrlForAvailableHeightInPX(item, parentHeight);

            ImageLoader.instance().loadASYNC(imgurl, imgView);

        }
    }

只要您希望RecyclerView根据宽高比显示不同宽度的图像,我相信这是您的最佳选择。