The code below is a custom view - it draws a circle, adds notches according to a scale and adds the scale text. This was derived from Mind The Robot's excellent tutorial on creating a vintage thermometer. http://mindtherobot.com/blog/272/android-custom-ui-making-a-vintage-thermometer/
This code works fine on devices running up to Jelly Bean 4.1.2 but breaks on 4.2. On 4.2 the numbers no longer get drawn around the circle but seem to be spread all over the screen.The code worked fine on a Nexus 7 until it got the 4.2 update so it can't be a device issue. I have tested it on a Nexus S running 4.1.2 and a Nexus 4 running 4.2 it works fine on the Nexus S but not on the Nexus 4.
Unfortunately as a new user I can't post screenshots, I'll try to describe it: The numbers display correctly for the first half of the dial, the rest of the numbers are scattered across the screen.
I have looked at the 4.2 change log but I can't see anything that would cause this to happen. I have looked for similar issues on-line but these all seem to be to do with hardware acceleration - I have tried various combinations of setting hardware acceleration in the manifest but nothing has any impact.
I'd really appreciate any input on what might be causing this to happen.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
public class AneroidView extends View {
// drawing tools
private RectF rimRect;
private RectF faceRect;
private Paint scalePaint;
private RectF scaleRect;
private Paint backgroundPaint;
// end drawing tools
private Bitmap background; // holds the cached static part
private int totalNotches = 130;
private int incrementPerLargeNotch = 10;
private int incrementPerSmallNotch = 1;
private float degreesPerNotch = 360.0f / totalNotches;
private int scaleCenterValue = 1000; // the one in the top center (12 o'clock)
private int scaleMinValue = 935;
private int scaleMaxValue = 1065;
public AneroidView(Context context) {
super(context);
init(context, null);
}
public AneroidView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AneroidView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
rimRect = new RectF(0.1f, 0.1f, 0.9f, 0.9f);
float rimSize = 0.02f;
faceRect = new RectF();
faceRect.set(rimRect.left + rimSize, rimRect.top + rimSize,
rimRect.right - rimSize, rimRect.bottom - rimSize);
scalePaint = new Paint();
scalePaint.setStyle(Paint.Style.STROKE);
scalePaint.setColor(Color.rgb(49, 79, 79));
scalePaint.setStrokeWidth(0.005f);
scalePaint.setAntiAlias(true);
scalePaint.setTextSize(0.045f);
scalePaint.setTypeface(Typeface.SANS_SERIF);
scalePaint.setTextScaleX(0.8f);
scalePaint.setTextAlign(Paint.Align.CENTER);
// The scale rectangular is located .10 from the outer rim.
float scalePosition = 0.10f;
scaleRect = new RectF();
scaleRect.set(faceRect.left + scalePosition, faceRect.top + scalePosition,
faceRect.right - scalePosition, faceRect.bottom - scalePosition);
}
private void drawScale(Canvas canvas) {
// Draw a large notch every large increment, and a small
// notch every small increment.
canvas.drawOval(scaleRect, scalePaint);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
for (int i = 0; i < totalNotches; ++i) {
float y1 = scaleRect.top;
float y2 = y1 - 0.015f;
float y3 = y1 - 0.025f;
int value = notchToValue(i);
if (i % (incrementPerLargeNotch/incrementPerSmallNotch) == 0) {
if (value >= scaleMinValue && value <= scaleMaxValue) {
// draw a nick
canvas.drawLine(0.5f, y1, 0.5f, y3, scalePaint);
String valueString = Integer.toString(value);
// Draw the text 0.15 away from y3 which is the long nick.
canvas.drawText(valueString, 0.5f, y3 - 0.015f, scalePaint);
}
}
else{
if (value >= scaleMinValue && value <= scaleMaxValue) {
// draw a nick
canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);
}
}
canvas.rotate(degreesPerNotch, 0.5f, 0.5f);
}
canvas.restore();
}
private int notchToValue(int value) {
int rawValue = ((value < totalNotches / 2) ? value : (value - totalNotches)) * incrementPerSmallNotch;
int shiftedValue = rawValue + scaleCenterValue;
return shiftedValue;
}
private void drawBackground(Canvas canvas) {
if (background != null)
canvas.drawBitmap(background, 0, 0, backgroundPaint);
}
@Override
protected void onDraw(Canvas canvas) {
drawBackground(canvas);
float scale = (float) getWidth();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(scale, scale);
canvas.restore();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
regenerateBackground();
}
private void regenerateBackground() {
// free the old bitmap
if (background != null) {
background.recycle();
}
background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas backgroundCanvas = new Canvas(background);
float scale = (float) getWidth();
backgroundCanvas.scale(scale, scale);
drawScale(backgroundCanvas);
}
}