Android Fresco:绘制不同类型的图像形状

时间:2016-04-14 06:02:55

标签: android android-imageview android-drawable android-bitmap fresco

Fresco内置支持圆形图像和圆角,但其他形状如钻石或平行四边形等等呢?

通过使用BitmapShader的自定义drawable,使用标准ImageView很简单。例如,以下自定义Drawable接收图像位图和斜率高度,使ImageView看起来像这样的图片:

enter image description here

public class MaskDrawable extends Drawable {
    private Paint mPaint;
    private Path mPath;
    private int mSlopeHeight;

    public MaskDrawable(Bitmap bitmap, int slopeHeight) {
        BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(shader);
        mSlopeHeight = slopeHeight;

        mPath = new Path();
    }

    @Override
    public void draw(Canvas canvas) {
        Rect bounds = getBounds();

        mPath.moveTo(0, 0);
        mPath.lineTo(0, bounds.bottom);
        mPath.lineTo(bounds.right, bounds.bottom - mSlopeHeight);
        mPath.lineTo(bounds.right, 0);
        canvas.drawPath(mPath, mPaint);
    }

为了用Fresco做到这一点,我需要图像的位图,但我不知道该怎么做。我读到我可以直接从ImagePipeline获取Bitmap,但是随之而来的是许多陷阱。在一种情况下,返回的Bitmap是短暂的,不应该用于在屏幕上绘制,在另一种情况下我得到一个CloseableReference,我需要在某些时候释放,这对我来说是不清楚的。到目前为止,我在网上看到的是类似于获取Bitmap的代码:

ImagePipeline imagePipeline = Fresco.getImagePipeline();

        ImageRequest imageRequest = ImageRequestBuilder
                .newBuilderWithSource(uri)
                .setRequestPriority(Priority.HIGH)
                .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
                .build();

        DataSource<CloseableReference<CloseableBitmap>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, getContext());

        DataSubscriber<CloseableReference<CloseableBitmap>> dataSubscriber =
                new BaseDataSubscriber<CloseableReference<CloseableBitmap>>() {
                    @Override
                    protected void onNewResultImpl(DataSource<CloseableReference<CloseableBitmap>> dataSource) {
                        mBitmapRef = dataSource.getResult();
                        // Get the bitmap here and use it in my custom drawable?
                    }

                    @Override
                    protected void onFailureImpl(DataSource<CloseableReference<CloseableBitmap>> dataSource) {
                    }
                };

        dataSource.subscribe(dataSubscriber, UiThreadImmediateExecutorService.getInstance());

我还没有尝试过,并且想知道是否有人可以提供一个有效的解决方案而不是我迄今为止从不同地方收集的比特和字节。它必须正确完成,否则我很容易泄漏内存,这首先打破了从一开始就使用Fresco的整个想法。

1 个答案:

答案 0 :(得分:0)

在处理视图时,您不需要也不建议使用imagepipeline。

一种方法是在后处理器中管理这些位图。您需要覆盖流程方法,使用相同的BitmapShader,绘制,画布实现,使用PlatformBitmapFactory createBitmap创建可清除位图CloseableReference,最后在完成位图时关闭引用。

查看更多内容 http://frescolib.org/docs/modifying-image.html

修改

以下是我在得到王杰的帮助后想出的最终实施情况。以下代码段将图像放置在我在问题中显示的形状中。

mSimpleDraweeView = (SimpleDraweeView) findViewById(R.id.shaped_picture);
final int slopeHeight = 100;

Postprocessor maskProcessor = new BasePostprocessor() {
    @Override
    public CloseableReference<Bitmap> process(Bitmap sourceBitmap, PlatformBitmapFactory bitmapFactory) {
        // Get the size of the downloaded bitmap
        final int width = sourceBitmap.getWidth();
        final int height = sourceBitmap.getHeight();

        // Create a new bitmap and use it to draw the shape that we want.
        CloseableReference<Bitmap> bitmapRef = bitmapFactory.createBitmap(width, height);
        try {
            Bitmap destBitmap = bitmapRef.get();

            // Create canvas using the new bitmap we created earlier
            Canvas canvas = new Canvas(destBitmap);

            // Set up the Paint we will use for filling in the shape
            // BitmapShader will fill the shape with the downloaded bitmap
            BitmapShader shader = new BitmapShader(sourceBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setShader(shader);

            // Set up the actual shape. Modify this part with any shape you want to have.
            Path path = new Path();
            path.moveTo(0, 0);
            path.lineTo(0, height);
            path.lineTo(width, height - slopeHeight);
            path.lineTo(width, 0);

            // Draw the shape and fill it with the paint
            canvas.drawPath(path, paint);

            return CloseableReference.cloneOrNull(bitmapRef);
        }
        finally {
            CloseableReference.closeSafely(bitmapRef);
        }
    }
};

ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
        .setPostprocessor(maskProcessor)
        .build();

DraweeController controller = Fresco.newDraweeControllerBuilder()
        .setImageRequest(request)
        .setOldController(mSimpleDraweeView.getController())
        .build();

mSimpleDraweeView.setController(controller);