Number inside circle - android

What is the best way for draw a number inside circle drawed on canvas by drawCircle?
Then this circle can be dragged by user, when circle is empty I donĀ“t have problems.

This will draw text centered at centerX, centerY
Rect rect = new Rect();
paint.getTextBounds(text, 0, text.length(), rect);
float x = centerX - rect.width() / 2;
FontMetrics fm = paint.getFontMetrics();
float y= centerY - (fm.descent + fm.ascent) / 2;
canvas.drawText(text, x, y, paint);

Related

How to get text BaseLine from Paint

I am trying to draw a text at the centre of canvas, Since canvas starts drawing text at BaseLine, I am not able to Place it at centre. If i can get the baseLine, then i can calculate the centre.
I have tried with paint.getFontMetrics() this gives ascent and descent but not baseLine.
Did you try this code
private void drawCenter(Canvas canvas, Paint paint, String text) {
canvas.getClipBounds(r);
int cHeight = r.height();
int cWidth = r.width();
paint.setTextAlign(Paint.Align.LEFT);
paint.getTextBounds(text, 0, text.length(), r);
float x = cWidth / 2f - r.width() / 2f - r.left;
float y = cHeight / 2f + r.height() / 2f - r.bottom;
canvas.drawText(text, x, y, paint);
}
All the calculations of paint.getFontMetrics() will happen with respect to baseLine. So if i just subtract (getMeasuredHeight() / 2f) - (fontMetrics.ascent / 2f) it will draw from center

Draw circle on start and end point of an Arc

Hi im having difficulties on drawing dots on arc's both ends (start and end)
Although I can draw arc on canvas. Heres my sample code for drawing arc.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = (float) getWidth();
float height = (float) getHeight();
float radius;
if (width > height) {
radius = height / 4;
} else {
radius = width / 4;
}
float center_x, center_y;
final RectF oval = new RectF();
center_x = width / 2;
center_y = height / 2;
oval.set(center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius);
float percent = 25;
float arcRadius = 360;
float angle = arcRadius * (percent/100);
canvas.drawArc(oval, 270, 360, false, trackpaint);
canvas.drawArc(oval, 270, angle, false, arcPaint);
}
the only missing is putting circles on start and end points of the arc. I've tried this link but it doest work Calculate Arc Center Point, Knowing It's Start and End Degrees. Any help will be much appreciated. Thank you
the coordinate of the start point is:
double startX = Math.cos(Math.toRadians(270)) * radius + center_x;
double startY = Math.sin(Math.toRadians(270)) * radius + center_y;
the coordinate of the end point is:
double endX = Math.cos(Math.toRadians(270 + angle)) * radius + center_x;
double endY = Math.sin(Math.toRadians(270 + angle)) * radius + center_y;
and then you can draw circle using the start point and end point:
canvas.drawCircle(startX, startY, 10, paint);
canvas.drawCircle(endX, endY, 10, paint);
Get path from the ARC
Use PathMeasure class to retrieve Path length and path TAN, using starting or Ending X and Y coordinates of the ARC
Use this X and Y coordinates to draw circle.
Example for circle at the start of the ARC:
final Path mPath = new Path();
mPath.addArc(oval, startAngle, sweepAngle);
PathMeasure pm = new PathMeasure(mPath, false);
float[] xyCoordinate = { arcStarting.x , arcStarting.y };
float pathLength = pm.getLength();
pm.getPosTan(0, xyCoordinate, null);//"0 for starting point"
PointF point = new PointF(xyCoordinate[0], xyCoordinate[1]);
canvas.drawCircle(point.x, point.y, 10, YourPaintHere)

Draw Text on scaled Canvas on Android

i am drawing a text on a scaled canvas like this:
Rect bounds = new Rect();
paint.getTextBounds(fct.getText(), 0, fct.getText().length(), bounds);
float scaleX = postcard.getWidth() / fct.getContainerWidth();
float scaleY = postcard.getHeight() / fct.getContainerHeight();
float textXpos = fct.getPositionX();
float textYpos = fct.getPositionY();
float rotateX = textXpos + bounds.exactCenterX();
float rotateY = textYpos + bounds.exactCenterY();
canvas.save();
canvas.scale(scaleX, scaleY);
canvas.rotate(fct.getRotation(), rotateX, rotateY);
canvas.drawText(fct.getText(), textXpos, textYpos, paint);
canvas.restore();
The X position of the drawn text is completly correct but the Y position is wrong.
The text is drawn above the expected position.
So how to draw it correctly?

Android fill in part of a path?

I have a shape that I'm drawing with a path. I'm filling that shape in with a gradient and then I need to put another gray area ontop of that gradient dependent upon a %. I'm using path.quadTo to make my shape so I don't know the y coordinate of the top line to properly intersect it. This is what I'm getting when I just set it to the maximum y:
The white stroke is the image I'm trying to partially fill in. The right gray area I want to keep, but I need to get rid of the left gray area. Any ideas? This is what I'm trying so far:
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
Path grayPath = new Path();
float x1,y1,x3,y3,x2,y2;
float x1g,x2g;
int width = canvas.getWidth();
int height = canvas.getHeight();
gradientPaint.setShader(new LinearGradient(0, height,width,height, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, new float[] {0,0.6f,1}, Shader.TileMode.REPEAT));
x1 = 0;
y1 = (float) (height * .90);
x2 = (float) (width * .75);
y2 = (float) (height * .50);
x3 = width;
y3 = (float) (height * .10);
x2g = (float) (width*.50);
//Ramp
path.moveTo(x1, y1);
path.quadTo(x2, y2, x3, y3);
//Down
path.lineTo(x3, y1+50);
//Back
path.lineTo(x1, y1+50);
//Up
path.lineTo(x1, y1);
//Ramp
grayPath.moveTo(x1, y1);
grayPath.quadTo(x2, y2, x3, y3);
//Down
grayPath.lineTo(x3, y1+50);
//Back
grayPath.lineTo(x2g, y1+50);
//Up
grayPath.lineTo(x2g, y3);
grayPath.setFillType(FillType.WINDING);
//Draw for shiny fill
//canvas.drawPath(path, gradientPaint);
//Draw for grayness
canvas.drawPath(grayPath, grayPaint);
//Draw for stroke!
canvas.drawPath(path, strokePaint);
}
Clipping is what I was looking for and is a much simpler solution:
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
float x1,y1,x3,y3,x2,y2;
int width = canvas.getWidth();
int height = canvas.getHeight();
gradientPaint.setShader(new LinearGradient(0, height,width,height, new int[]{Color.RED, Color.YELLOW, Color.GREEN}, new float[] {0,0.6f,1}, Shader.TileMode.REPEAT));
//Start at the left side, 10% up
x1 = 0;
y1 = (float) (height * .90);
x2 = (float) (width * .75);
y2 = (float) (height * .50);
x3 = width;
y3 = (float) (height * .10);
//Ramp
path.moveTo(x1, y1);
path.quadTo(x2, y2, x3, y3);
//Down
path.lineTo(x3, y1+50);
//Back
path.lineTo(x1, y1+50);
//Up
path.lineTo(x1, y1);
//Create Gray Rect with %
Rect rect = new Rect((int)(width*.50),0,(int) x3, (int) y1+50);
//CLIP IT
canvas.clipPath(path);
//Draw for shiny fill
canvas.drawPath(path, gradientPaint);
//Draw for grayness
canvas.drawRect(rect, grayPaint);
//Draw for stroke!
canvas.drawPath(path, strokePaint);
}

Strange behaviour of `drawTextOnPath()` with hardware accelration

In hardware accelerated custom View added in ScrollView or ListView both of the following code snippets produces same result: (please ignore best practises for a sec)
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// centering stuff
float centerX = getWidth() / 2f;
float centerY = getHeight() / 2f;
float size = 80;
float halfSize = size / 2f;
float left = centerX - halfSize;
float top = centerY - halfSize;
RectF oval = new RectF(left, top, left + size, top + size);
Path path = new Path();
path.addArc(oval, 160, 359);
Paint paint = new Paint();
paint.setTextSize(30);
paint.setStyle(Style.STROKE);
canvas.drawTextOnPath("Hello world", path, 0, 0, paint); //<--- line A
canvas.drawCircle(centerX, centerY, 10, paint); //<--- line B
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// centering stuff
float centerX = getWidth() / 2f;
float centerY = getHeight() / 2f;
float size = 80;
float halfSize = size / 2f;
float left = centerX - halfSize;
float top = centerY - halfSize;
RectF oval = new RectF(left, top, left + size, top + size);
Path path = new Path();
path.addArc(oval, 160, 359);
Paint paint = new Paint();
paint.setTextSize(30);
paint.setStyle(Style.STROKE);
canvas.drawCircle(centerX, centerY, 10, paint); //<--- line B
canvas.drawTextOnPath("Hello world", path, 0, 0, paint); //<--- line A
}
Same Result:
But with later code snippet, as soon as you scroll the ScrollView (I have invisible dummy View below so I can scroll) and helloworld touches ActionBar, something very intersting happens and you see something that intelligent humankind used to see in old Windows OS .
I know drawTextOnPath() is not supported in hardware accelration mode, but then why it works if you call it first?
drawTextOnPath() is supported by hardware acceleration after Android 4.1
This is mentioned officially here: https://code.google.com/p/android/issues/detail?id=37925
but the next comment seems to indicate your problem in a way so maybe a bug.
Of course for pre 4.1 just dont make it use HW accel - Set a software layer type on your View by calling View.setLayerType(View.LAYER_TYPE_SOFTWARE, null) and try to get a tradeoff on perf vs errors

Categories

Resources