【问题标题】:Android Fresco: drawing different kind of image shapesAndroid Fresco:绘制不同类型的图像形状
【发布时间】:2016-04-14 06:02:55
【问题描述】:

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

通过使用 BitmapShader 的自定义可绘制对象来处理标准 ImageView 很简单。例如,下面的自定义 Drawable 接收图像 Bitmap 和坡度高度,使 ImageView 看起来像这样:

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 获取位图,但它附带了许多陷阱。在一种情况下,返回的位图是短暂的,不应该用于在屏幕上绘制,而在另一种情况下,我会得到一个 CloseableReference,我需要在某个我不清楚的时候释放它。到目前为止,我在网上看到的是与此类似的用于获取位图的代码:

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 的整个想法。

【问题讨论】:

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


    【解决方案1】:

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

    一种方法是在后处理器中管理这些位图。需要重写 process 方法,使用相同的 BitmapShader、paint、canvas 实现,使用 PlatformBitmapFactory createBitmap 创建可清除位图 CloseableReference,最后在完成位图后关闭引用。

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

    编辑

    以下是我在得到王杰的帮助后想出的最终实现。以下代码 sn-p 将图像放置在我在问题中提出的形状中。

    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);
    

    【讨论】:

    • 我已经更新了答案以提供具体的解决方案实施,以防其他人遇到这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    相关资源
    最近更新 更多