I am trying to draw a text on curved path. But when I scale up the canvas, text gets blurred.
Here's the code I've tried
public void draw(Canvas canvas) {
float midX = (maxX + minX) / 2;
float midY = (maxY + minY) / 2;
canvas.save();
canvas.translate(minX, minY);
canvas.scale(this.scaleX, this.scaleY);
if (curvingAngle != 0) {
drawCurveText(canvas, 0f, 0f, 1f);
} else
canvas.drawText(text, mOrigin[0], mOrigin[1], textPaint);
canvas.restore();
}
private void drawCurveText(Canvas canvas,float offsetX, float offsetY, float scale) {
// Path Calculation
Path textPath;
canvas.drawTextOnPath(text, this.textPath, hOffset, 0.0f, this.getPaint());
}
It gives following results
Before Scale
After Scale
The same code without curvingAngle (canvas.drawText) works perfectly with scaling.
Any help would be appreciated...
Related
I am trying to create a pentagon shaped polygon which can be resized by dragging one of its vertices. I tried some code from this question on SO but later realised that the code is specifically written for a rectangle shape. I tried modifying the code in the onDraw() method but later refactored it to the way it was earlier after realising that it is of no use.
Any help?
So here's a code I just wrote to draw a pentagon in the canvas. You pretty much have the vertices which you can edit on the onTouchEvent.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int heigth = getHeight();
// not required, but just to move it to the middle
float centerX = width / 2.f;
float centerY = heigth / 2.f;
// vertices
float p1x = 100.f + centerX;
float p1y = 0.f + centerY;
float p2x = 0.f + centerX;
float p2y = -80.f + centerY;
float p3x = -100.f + centerX;
float p3y = 0.f + centerY;
float p4x = -80.f + centerX;
float p4y = 80f + centerY;
float p5x = 80.f + centerX;
float p5y = 80.f + centerY;
Path path = new Path();
path.moveTo(p1x, p1y);
path.lineTo(p2x, p2y);
path.lineTo(p3x, p3y);
path.lineTo(p4x, p4y);
path.lineTo(p5x, p5y);
path.lineTo(p1x, p1y);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawPath(path, paint);
}
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)
I'm starting with Android Wear and I want to make a circle animation, making grow.
I know how to do it, I think, but it's doing it very very slow, hope you can help me
I have this class variable
Paint mAnimation;
intialized on the method OnCreate
mAnimation = new Paint(Paint.ANTI_ALIAS_FLAG);
mAnimation.setStyle(Paint.Style.FILL);
mAnimation.setColor(Color.GREEN);
and on the OnDraw method I have
#Override
public void onDraw(Canvas canvas, Rect bounds) {
int width = bounds.width();
int height = bounds.height();
float centerX = width / 2f;
float centerY = height / 2f;
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
canvas.drawCircle(0, centerY, radiusPlus, mAnimation);
radiusPlus += 20;
}
The animation is "correct", but is very slow, like if was paused.
Thanks!!
EDIT
I found a example and now I finally found why. I didn't invalidate the view at the end of the OnDraw. Now It's working fine. Thanks.
#Override
public void onDraw(Canvas canvas, Rect bounds) {
int width = bounds.width();
int height = bounds.height();
float centerX = width / 2f;
float centerY = height / 2f;
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
canvas.drawCircle(0, centerY, radiusPlus, mAnimation);
radiusPlus += 5;
if (isVisible() && !isInAmbientMode()) {
invalidate();
}
}
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
I'm learning Android and now I'm experimenting with the Canvas class.
I would like to draw a regular (equilateral) triangle inscribed into a known circle.
I think there must be a easier way to do it than getting into trigonomery, pythagoras,...
Doing the trig is the most straightforward method that I've found. Below is a function for drawing an equilateral triangle in the normal, "pointing upward" orientation. I've posted a more sophisticated implementation here that also handles rotating the triangle.
private void drawCircumscribedTriangle(Canvas canvas, float circleCenterX, float circleCenterY, float radius, Paint paint) {
float xOffsetFromCenter = FloatMath.cos((float)Math.PI/6) * radius;
float yOffsetFromCenter = FloatMath.sin((float)Math.PI/6) * radius;
canvas.drawLine(circleCenterX, circleCenterY - radius, circleCenterX + xOffsetFromCenter, circleCenterY + yOffsetFromCenter, paint);
canvas.drawLine(circleCenterX + xOffsetFromCenter, circleCenterY + yOffsetFromCenter, circleCenterX - xOffsetFromCenter, circleCenterY + yOffsetFromCenter, paint);
canvas.drawLine(circleCenterX - xOffsetFromCenter, circleCenterY + yOffsetFromCenter, circleCenterX, circleCenterY - radius, paint);
}
Thanks to Acj, I got it, But it wasn't exactly what I wanted, because I wanted it to be filled (It's my fault because I didn't specify it).
Anyway, I adapted Acj's code to my needs, and here it is:
private void drawCircumscribedTriangle(Canvas canvas, float circleCenterX, float circleCenterY, float radius, Paint paint) {
float xOffsetFromCenter = FloatMath.cos((float)Math.PI/6) * radius;
float yOffsetFromCenter = FloatMath.sin((float)Math.PI/6) * radius;
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
path.moveTo(circleCenterX, circleCenterY - radius);
path.lineTo(circleCenterX + xOffsetFromCenter, circleCenterY + yOffsetFromCenter);
path.lineTo(circleCenterX - xOffsetFromCenter, circleCenterY + yOffsetFromCenter);
path.lineTo(circleCenterX, circleCenterY - radius);
path.lineTo(circleCenterX, circleCenterY - radius);
canvas.drawPath(path, paint);
}
Once more, all the merit is for Acj
As FloatMath.cos(float) is deprecated since API 23, this answer to a tricky equilateral question needs the following lines of its code updating to
float xOffsetFromCenter = ((float)Math.PI/6) * radius;
float yOffsetFromCenter = ((float)Math.PI/6) * radius;