M'hamed M'hamed - 2 months ago 39
Android Question

Customize a ProgressBar to become a Thermometer

How to customize a ProgressBar to look like a Thermometer ? with the possibility to change color.

Thermometer bleu full Thermometer bleu empty Thermometer red full Thermometer red empty

My suggestion was to rotate the progressBar 90° to become vertical then have it overlay an image of an empty Thermometer but it's bad and messy solution.

I Think the best will be to either to extends View or ProgressBar class and customize the draw method but I have no idea how to draw Thermometer, any Help would be appreciated.

Answer

First I would provide 2 setters, one for color and one for the temperature value, normalized from 0 ... 1, where 0 means no visible bar, and 1 means a fully visible bar.

public void setColor(int color) {
    mColor = color;
    invalidate(); // important, this triggers onDraw
}

public void setValue(float value) {
    mValue = -(value - 1);
    invalidate(); // important, this triggers onDraw
}

Notice for value, I reverse the value, since we draw the bar from bottom up, instead from top down. It makes sense in the canvas.drawRect method.

If your CustomView may have custom sizes, set your size of the progressBar (I refer to the inner bar as progressBar) in onSizeChanged, as this gets called when the View has changed it's size. If it is a fixed size, you can just provide those values statically in an init function or the constructor.

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    mProgressRect = new Rect(
    /*your bar left offset relative to base bitmap*/,
    /*your bar top offset relative to base bitmap*/,
    /*your bar total width*/,
    /*your max bar height*/
    );
}

Then in ondraw, take these values into account and draw accordingly.

  • First draw the Bitmap, depending on your selected color (I would provide the thermometer base as a Bitmap, as long as it does not have to be completely dynamically drawn (special requirements)
  • Then draw the progress bar, with an height based on mValue * totalHeight of the bar, using the color provided in the setter.

For example:

@Override
protected void onDraw(Canvas canvas) {
    // draw your thermometer base, bitmap based on color value
    canvas.drawBitmap( /*your base thermometer bitmap here*/ );

    // draw the "progress"
    canvas.drawRect(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.right, mProgressRect.bottom, mPaint);

}

Hope that helps.

P.S.: If you want to have the thermometer base image also dynamically drawn, it's a slightly different story, it would involve creating a path first and draw it with a Paint object, instead of drawing the bitmap.

EDIT:

Even better, if you want a simple solution for the "roundness" of the bar, draw a line instead a rect.

Define a line paint object like this:

    mPaint = new Paint();
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(20); // thickness of your bar

then in onDraw, instead drawRect:

    // draw the "progress"
    canvas.drawLine(mProgressRect.left, mProgressRect.top + (mValue * mProgressRect.bottom - mProgressRect.top), mProgressRect.left, mProgressRect.bottom, mPaint);

Be sure to adjust your mProgressRectaccordingly.