我在交错的网格布局中有一个带有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;
}