Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invert paint color based on background

Tags:

android

I am writing a custom progress bar. I would like to create an effect similar to

enter image description here

where the "50%" text color changes dynamically to white while the black bar progresses right. Is that possible using "simple" solutions? I looked up PorterDuff, ColorFilters, xFermodes, nothing seems to work. Any ideas? ATM my code looks sth like this:

    Rect r = new Rect(1, 1, m_width-1, m_height-1);
    canvas.drawRect(r, pWhiteFill);
    r = new Rect(1, 1, progressWidth, m_height-1);
    canvas.drawRect(r, pBlackFill);     
    canvas.drawText(String.valueOf(progress)+"%", m_width/2, m_height/2, pBlackTxtM);

Is there a way to modify pBlackTxtM paint to change color based on whats drawn below it 'on the canvas'?

like image 863
Chris K. Avatar asked Apr 08 '14 16:04

Chris K.


1 Answers

Even if the question is quite old I'd like to share the solution to this.

You can't do this using an "inverting" Paint, but you can achieve it using clipping.

The idea is to draw the text twice, once in black and once in white color, while setting the clipping region to match respective part of the bar.

Here is some code to outline the idea:

// store the state of the canvas, so we can restore any previous clipping
canvas.save();

// note that it's a bad idea to create the Rect during the drawing operation, better do that only once in advance
// also note that it might be sufficient and faster to draw only the white part of the bar
Rect r = new Rect(1, 1, m_width-1, m_height-1);
canvas.drawRect(r, pWhiteFill);

// this Rect should be created when the progress is set, not on every drawing operation
Rect r_black = new Rect(1, 1, progressWidth, m_height-1);
canvas.drawRect(r_black, pBlackFill);

// set the clipping region to the black part of the bar and draw the text using white ink
String text = String.valueOf(progress)+"%";
canvas.cliprect(r_black);
canvas.drawText(text, m_width/2, m_height/2, pWhiteTxtM);

// draw the same text again using black ink, setting the clipping region to the complementary part of the bar
canvas.clipRect(r, Region.Op.XOR);
canvas.drawText(text, m_width/2, m_height/2, pBlackTxtM);

canvas.restore();
like image 82
Marten Avatar answered Oct 01 '22 02:10

Marten