Android Fresco: рисование различных форм изображений

Fresco имеет встроенную поддержку круглых изображений и закругленных углов, но как насчет других форм, таких как ромб или параллелограмм и т. д.?

Это просто сделать со стандартным ImageView с помощью пользовательского рисования, использующего BitmapShader. Например, следующий пользовательский Drawable получает растровое изображение изображения и высоту наклона, чтобы сделать 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 с самого начала.


person Nimrod Dayan    schedule 14.04.2016    source источник


Ответы (1)


Вам не нужно, а также не рекомендуется использовать imagepipeline, когда вы имеете дело с представлением.

Один из способов — управлять этими растровыми изображениями в постпроцессоре. Вам нужно переопределить метод процесса, использовать ту же реализацию BitmapShader, paint, canvas, использовать 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);
person Jie Wang    schedule 14.04.2016
comment
Я обновил ответ, чтобы иметь конкретную реализацию решения на случай, если кто-то еще столкнется с этой проблемой. - person Nimrod Dayan; 14.04.2016