You're trying to solve this problem using a view hierarchy like this:
Problem is, in this position, InverterView
has no control over how ListView
is drawn. But you know who does have control over how ListView
is drawn? ListView
's parent layout does. In other words, what you really want is a hierarchy like this:
Now InverterLayout
is responsible for drawing ListView
, and can apply effects to it.
class InverterLayout extends FrameLayout
{
// structure to hold our color filter
private Paint paint = new Paint();
// the color filter itself
private ColorFilter cf;
// the rectangle we want to invert
private Rect inversion_rect = new Rect(100, 100, 300, 300);
public InverterLayout(Context context)
{
super(context);
// construct the inversion color matrix
float[] mat = new float[]
{
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0
};
cf = new ColorMatrixColorFilter(new ColorMatrix(mat));
}
@Override protected void dispatchDraw(Canvas c)
{
// create a temporary bitmap to draw the child views
Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
Canvas cc = new Canvas(b);
// draw them to that temporary bitmap
super.dispatchDraw(cc);
// copy the temporary bitmap to screen without the inversion filter
paint.setColorFilter(null);
c.drawBitmap(b, 0, 0, paint);
// copy the inverted rectangle
paint.setColorFilter(cf);
c.drawBitmap(b, inversion_rect, inversion_rect, paint);
}
}
When using this, ensure your child view has its own background. If the view is transparent and the window background shows through, that window background will not be inverted, because the InverterLayout
has no control over how the window is drawn.