使用Picasso转换图像以匹配ImageView宽度并在RecyclerView中保持纵横比

时间:2016-11-01 21:04:36

标签: android imageview android-recyclerview picasso

我在交错的网格布局中有一个带有CardViews的RecyclerView。每个CardView都有一个自定义可调高度ImageView。我正在使用Picasso将图像加载到ImageView中。

我试图先将图像转换为与ImageView的宽度相匹配,然后设置高度以保持纵横比。然后我尝试调整ImageView的高度以匹配图像。

所有内容都适用于第一次加载,但是当我向下滚动时,我的自定义转换无法获得ImageView的宽度,它只返回0,这会导致应用程序崩溃。

我尝试使用此post中建议的getViewTreeObserver,但之后只加载前四张图片,接下来的几张图片为空白,然后前四张图片在错误的CardView中重复出现。

这是我正确加载但在滚动时崩溃的代码:

Recycler Adapter

public class PlacesRecyclerAdapter extends 
RecyclerView.Adapter<PlacesRecyclerAdapter.PlacesView> {

    ...

    @Override
    public void onBindViewHolder(final PlacesView placesView, final int i) {

        Target target = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                float ratio = (float) bitmap.getHeight() / (float) bitmap.getWidth();

                placesView.placeImage.setAspectRatio(ratio);
                placesView.placeImage.setImageBitmap(bitmap);
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };
        placesView.placeImage.setTag(target);

        // Setup details variables
        final Business place = mPlaces.get(i);
        String photo = place.getImage_url();

        // Load Image with Picasso
        Picasso.with(mContext)
                .load(photo)
                .transform(new FitToViewTransformation(placesView.placeImage))
                .into(target);
    }

    ...
}

自定义转换

public class FitToViewTransformation implements Transformation {
    private DynamicHeightImageView mView;

    public FitToViewTransformation(DynamicHeightImageView view) {
        mView = view;
    }

    @Override
    public Bitmap transform(Bitmap source) {
        int targetWidth = mView.getWidth(); // This returns the width on the first page load but on scrolling returns 0
        Log.v("FitToView:", "Target width: " + targetWidth);

        double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
        int targetHeight = (int) (targetWidth * aspectRatio);


        Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
        if (result != source) {
            // Same bitmap is returned if sizes are the same
            source.recycle();
        }
        return result;
    }

    @Override
    public String key() {
        return "transformation" + " desiredWidth";
    }
}

更新1(失败)

我继续尝试再次尝试OnGlobalLayoutListener,我仍然得到前四个图像,然后是四个空白图像,然后前四个再次显示。这就是我在onBindViewHolder中实现的方法:

placesView.placeImage.getViewTreeObserver()
        .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        placesView.placeImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        Picasso.with(mContext)
                .load(photo)
                .placeholder(R.drawable.cast_album_art_placeholder)
                .error(R.drawable.item_icon_parking)
                .transform(new FitToViewTransformation(placesView.placeImage))
                .into(target);
    }
});

更新2(成功......我猜)

所以我找到了一个解决办法,虽然我不太确定这是正确的做法。它确实有效,应用程序没有任何不需要的行为。我所做的就是在我的变换方法的开头添加一个空的while循环,如下所示:

@Override
public Bitmap transform(Bitmap source) {
    double aspectRatio = (double) source.getHeight() / (double) source.getWidth();

    while(mView.getWidth() == 0) {

    }

    int targetWidth = mView.getWidth();
    Log.v("FitToView:", "Target width: " + targetWidth);

    int targetHeight = (int) (targetWidth * aspectRatio);


    Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
    if (result != source) {
        // Same bitmap is returned if sizes are the same
        source.recycle();
    }

    return result;
}

0 个答案:

没有答案