将 Fresco 与 StaggeredGridLayoutManager 结合使用

Using Fresco with StaggeredGridLayoutManager

我遵循了 this 不错的教程,本地图像一切顺利。当尝试从本地图像更改为我通过 Fresco 加载到 SimpleDraweeView 中的图像时,我似乎无法让视图调整大小并在其他图像中错开。

我的布局看起来像这样(它是:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    card_view:cardUseCompatPadding="true"
    card_view:cardCornerRadius="8dp"
    android:layout_marginBottom="16dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/fresco_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            fresco:actualImageScaleType="fitXY"
            />
        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="13sp"
            android:text="@string/hello_world"
            android:textColor="#ffffff"
            android:layout_below="@+id/fresco_image"
            android:paddingBottom="8dp"
            android:paddingTop="8dp"
            android:gravity="center_horizontal"
            android:layout_alignParentBottom="true"
            android:background="#1976D2"/>
    </RelativeLayout>
</android.support.v7.widget.CardView>

以上膨胀为以下:

    <android.support.v7.widget.RecyclerView
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/text"
        android:scrollbars="vertical">
    </android.support.v7.widget.RecyclerView>

我试过的受票人:

  1. 将宽度或高度或两者设置为 "match_parent" 和 "wrap_content" 以及所有变体。 wrap_content 设置似乎没有 recommended
  2. 不同的宽高比,但这似乎会导致图像被裁剪并且全部统一 size/shape(不交错)
  3. scaleType 与上述的不同组合。

在受票人之外,我一直在查看 GitHub 的一些演示,但我似乎找不到任何交错视图的示例。

我确定这只是获得正确组合的设置的问题,但对于像我这样的人,我无法弄清楚该组合恰好是什么。

如有任何建议(或示例),我们将不胜感激!

更新 我们的后端实现 returns 每张图片的纵横比(以及 width/height)。我能够在 SimpleDraweeView 上设置宽高比并且它尊重这些值:

vDraweeView.setAspectRatio(fAspect);

如果我不必这样做会更酷,但显然视图在图像完全加载之前不知道它的大小。虽然这可能是调整视图大小的好时机,但这可能会导致显示跳动……不可取!!

这听起来对吗?

由于 SimpleDraweeView 在下载之前不知道图像的大小(并且不建议在最初绘制后调整大小,因为移动 UI 原因——也许是其他原因),我不得不设置下载图像之前的纵横比。这假设您在下载图像之前知道宽高比……我们在本例中就是这样做的。我在 recyclerview 适配器中这样做了。

设置纵横比的命令:

vDraweeView.setAspectRatio(fAspect);

您可以使用此替代 WrapContentDraweeView class:

public class WrapContentDraweeView extends GenericDraweeView {

private PipelineDraweeControllerBuilderSupplier mDraweeControllerBuilderSupplier;
private PipelineDraweeControllerBuilder mSimpleDraweeControllerBuilder;


public WrapContentDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
    super(context, hierarchy);
    this.init(context, (AttributeSet) null);
}

public WrapContentDraweeView(Context context) {
    super(context);
    this.init(context, (AttributeSet) null);
}

public WrapContentDraweeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.init(context, attrs);
}

public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.init(context, attrs);
}

@TargetApi(21)
public WrapContentDraweeView(Context context, AttributeSet attrs, int defStyleAttr,
                             int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    this.init(context, attrs);
}

private void init(Context context, @Nullable AttributeSet attrs) {

    if (!this.isInEditMode()) {
        mDraweeControllerBuilderSupplier = Fresco.getDraweeControllerBuilderSupplier();
        Preconditions.checkNotNull(mDraweeControllerBuilderSupplier,
                "SimpleDraweeView was not initialized!");
        this.mSimpleDraweeControllerBuilder = mDraweeControllerBuilderSupplier.get();
        if (attrs != null) {
            TypedArray gdhAttrs = context.obtainStyledAttributes(attrs,
                    R.styleable.SimpleDraweeView);

            try {
                if (gdhAttrs.hasValue(
                        R.styleable.SimpleDraweeView_actualImageUri)) {
                    this.setImageURI((Uri) Uri.parse(gdhAttrs.getString(
                            R.styleable.SimpleDraweeView_actualImageUri)),
                            (Object) null);
                } else if (gdhAttrs.hasValue(
                        R.styleable.SimpleDraweeView_actualImageResource)) {
                    int resId = gdhAttrs.getResourceId(
                            R.styleable.SimpleDraweeView_actualImageResource,
                            -1);

                }
            } finally {
                gdhAttrs.recycle();
            }
        }

    }
}

protected SimpleDraweeControllerBuilder getControllerBuilder() {
    return this.mSimpleDraweeControllerBuilder;
}

public void setImageURI(Uri uri) {
    this.setImageURI((Uri) uri, (Object) null);
}

public void setImageURI(@Nullable String uriString) {
    this.setImageURI((String) uriString, (Object) null);
}

public void setImageURI(Uri uri, @Nullable Object callerContext) {
    setAspectRatio(FrescoUtils.getAspectRatio(uri));
    ImageDecodeOptions decoderOptions = ImageDecodeOptions.newBuilder()
            .setDecodePreviewFrame(true)

            .build();
    ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)

            .setLocalThumbnailPreviewsEnabled(true)
            .setImageDecodeOptions(decoderOptions)

            .setPostprocessor(new BasePostprocessor() {
                @Override
                public CloseableReference<Bitmap> process(Bitmap sourceBitmap,
                                                          PlatformBitmapFactory bitmapFactory) {
                    int height = sourceBitmap.getHeight()/2;
                    int width = sourceBitmap.getWidth()/2;
                    if (width / (float) height < 0.5f) {
                        CloseableReference<Bitmap> cropReference = null;
                        CloseableReference<Bitmap> scaledReference = null;
                        try {
                            cropReference = bitmapFactory
                                    .createBitmap(sourceBitmap, 0, 0, width,
                                            (int) (width / 1.66f));
                            scaledReference = bitmapFactory
                                    .createScaledBitmap(cropReference.get(), getWidth(),
                                            (int) (getWidth() / 1.66f), false);
                            Bitmap bm = scaledReference.get();
                            Canvas canvas = new Canvas(bm);
                            Bitmap badge = getBadgeBitmap("长图");
                            int padding = (int) (getResources().getDisplayMetrics().density
                                    * 16);
                            canvas.drawBitmap(badge, bm.getWidth() - badge.getWidth() - padding,
                                    bm.getHeight() - badge.getHeight() - padding, new Paint());
                            return super.process(bm, bitmapFactory);
                        } finally {
                            if (cropReference != null) {
                                cropReference.close();
                            }
                            if (scaledReference != null) {
                                scaledReference.close();
                            }
                        }
                    }
                    return super.process(sourceBitmap, bitmapFactory);
                }
            })

            .build();

    DraweeController controller = this.mSimpleDraweeControllerBuilder
            .setImageRequest(imageRequest)
            .setCallerContext(callerContext)
            .setOldController(this.getController())
            .setAutoPlayAnimations(true)
            .setControllerListener(FrescoUtils.createControllerListener(this, uri))
            .setOldController(this.getController())


            .build();
    this.setController(controller);
}

public void setImageURI(@Nullable String uriString, @Nullable Object callerContext) {
    Uri uri = uriString != null ? Uri.parse(uriString) : null;
    this.setImageURI(uri, callerContext);
}



public void setImageResource(int resId) {
    super.setImageResource(resId);
}


private Bitmap getBadgeBitmap(String badge) {

    final DisplayMetrics dm = getResources().getDisplayMetrics();
    final float density = dm.density;
    final float scaledDensity = dm.scaledDensity;
    final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint
            .SUBPIXEL_TEXT_FLAG);
    textPaint.setColor(Color.WHITE);
    textPaint.setTypeface(Typeface.create("sans-serif-black", Typeface.NORMAL));
    textPaint.setTextSize(12 * scaledDensity);

    final float padding = 4 * density;
    final float cornerRadius = 2 * density;
    final Rect textBounds = new Rect();
    textPaint.getTextBounds(badge, 0, badge.length(), textBounds);
    final int height = (int) (padding + textBounds.height() + padding);
    final int width = (int) (padding + textBounds.width() + padding);
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.setHasAlpha(true);
    final Canvas canvas = new Canvas(bitmap);
    final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    backgroundPaint.setColor(Color.DKGRAY);
    RectF rectF = new RectF(0, 0, width, height);
    canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, backgroundPaint);
    // punch out the badge word, leaving transparency
  //        textPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

    // 居中
    Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
    int baseline = (int) (rectF.centerY() - (fontMetrics.top + fontMetrics.bottom) / 2);
    textPaint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(badge, rectF.centerX(), baseline, textPaint);
    return bitmap;
}
}

然后在您的布局中使用 WrapContentDraweeView 而不是 SimpleDraweeView 并使用您的包名称而不是 fresco package

<com.package.info.WrapContentDraweeView

       android:id="@+id/gridThumbnail"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"


    android:adjustViewBounds="true"
    fresco:placeholderImage="@drawable/placeholder"
    />

这比后端实现要好。

我遇到了类似的问题,但我使用的是 Glide。无论如何,请尝试使用下面的此属性设置您的 ImageView。我的 StaggeredGridView 有 2 列,效果很好。

   <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardCornerRadius="8dp"
        android:hardwareAccelerated="true"
        app:cardPreventCornerOverlap="false"
        android:elevation="0dp">

        <ImageView
            android:id="@+id/item_cover"
            android:layout_width="match_parent"
            android:scaleType="fitXY"
            android:adjustViewBounds="true"
            android:layout_height="wrap_content" />

    </android.support.v7.widget.CardView>

为了解决加载图像时的错误,我必须做的另一件事是在加载图像之前使用 PlaceHolder。

           Glide.with(context)
                .load(url)
                .placeholder(R.drawable.transparent_placeholder)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .crossFade()
                .into(itemCover)