Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best alternative to `canvas.clipRect` with `Region.Op.REPLACE`?

Tags:

android

canvas

Background

I'm working on a library that has a lot of canvas drawing instead of multiple views (available here).

The problem

As I work to improve it and make it work for our needs of the app (need some customization), I've noticed there are some lines that are marked as deprecated:

canvas.clipRect(0f, mHeaderHeight + mHeaderRowPadding * 2, mHeaderColumnWidth, height.toFloat(), Region.Op.REPLACE)

Thing is, I don't think there is a good candidate to replace this line of code with the newer APIs

What I've found

Looking at the docs, this is what's written:

This method was deprecated in API level 26. Region.Op values other than INTERSECT and DIFFERENCE have the ability to expand the clip. The canvas clipping APIs are intended to only expand the clip as a result of a restore operation. This enables a view parent to clip a canvas to clearly define the maximal drawing area of its children. The recommended alternative calls are clipRect(RectF) and clipOutRect(RectF);

So I tried using either of those functions, yet both of them caused issues with the drawing of how it used to be.

Looking at the deprecation, it seems that the function itself is marked, but not Region.Op.REPLACE :

enter image description here

So maybe it doesn't really have an alternative...

The questions

  1. What is the best alternative in this case?
  2. Why exactly was it deprecated?
  3. As opposed to some deprecated functions, I assume this one should be safe to still use in case I can't find an alternative, right?
like image 777
android developer Avatar asked May 08 '18 10:05

android developer


1 Answers

1: All methods that use custom Region.Op are deprecated now, so one can use only two method variants now: clipRect/clipPath (which represents Region.Op.INTERSECT) and clipOutRect/clipOutPath (which represents Region.Op.DIFFERENCE). To achieve function similar to Region.Op.REPLACE one must use save() and restore() methods.

So previously (with Op.REPLACE) you would call just:

canvas.clipRect(0, 0, 100, 100); // do some clipping
canvas.drawLine(...); // do some clipped drawing

canvas.clipRect(200, 200, 400, 400, Region.Op.REPLACE); // replace clipping region to completely different one
canvas.drawLine(...); // and some other drawing

But now you have to save and restore previous canvas state manually:

canvas.save();        // IMPORTANT: save current state of clip and matrix (i.e. unclipped state) (let's say it's state #1)
canvas.clipRect(0, 0, 100, 100); // do some clipping
canvas.drawLine(...); // do some clipped drawing
canvas.restore();     // IMPORTANT: get back to previously saved (unclipped) state of the canvas (restores state #1)

canvas.save(); // now save again the current state of canvas (clip and matrix) (it's state #2)
canvas.clipRect(200, 200, 400, 400); // now we can do some other clipping (as we would do with Region.Op.REPLACE before)
canvas.drawLine(...); // and some other drawing
canvas.restore(); // get back go previously saved state (to state #2)

Note Canvas is internally using stack, so you can even call save() multiple times at different moments. You just can't call canvas.restore() more times than the canvas.save() was called.

Also important note is that call to canvas.restore() changes the clip rect (to the same value it was when canvas.save() was called). So you must carefully place the restore() call after all the drawing methods that needs the applied clipping.

2: Probably because of some performance optimizations. I think I read somewhere (I couldn't find it now) that for hardware acceleration on GPU they can use only INTERSECT / DIFFERENCE clip operations and other ones must fall-back to CPU processing. That might be the reason.

EDIT: Here is some related answer, that since ICS with enabled HW acceleration some ClipRect ops are not supported.

3: As they say in documentation, it will stop working in Android P (probably only when targeting Android P):

As of API Level API level Build.VERSION_CODES.P only INTERSECT and DIFFERENCE are valid Region.Op parameters.

like image 169
Robyer Avatar answered Oct 10 '22 17:10

Robyer