I have implemented a long onDraw method which draws a set of rectangles. The rectangles are too small and I want them to appear bigger. But unfortunately I can't change the rectangle coordinates because they are stored in a database. So is there any way I can zoom in the canvas using canvas.scale() ?
I'm going to preface this answer by saying you will need to draw everything at 0,0 and then scale it, and finally translate it to behave properly.
Simply do the following in your onDraw method:
canvas.save();
canvas.translate(xValue, yValue);
canvas.scale(xScale, yScale)
/* draw whatever you want scaled at 0,0*/
canvas.restore();
xScale shrinks or stretches in the X direction,
yScale shrinks or stretches in the Y direction.
1.0 is the default for these, so 2.0 would stretch it by double and 0.5 would shrink it by half.
Example:
canvas.save();
canvas.translate(50, 50);
canvas.scale(0.5f, 0.5f);
canvas.drawRect(0.0, 0.0, 5.0, 5.0, paint);
canvas.restore();
This will draw a rectangle with length 5.0, and width 5.0, scale it down to 2.5 for length and width, and then move it to (50, 50).
The result will be a rectangle drawn as if you did this:
canvas.drawRect(50.0, 50.0, 52.5, 52.5, paint);
I hope this helps!
Related
I have a code to scale drawing canvas.
So i tried this code. i scale it but it moves down,
here is my code:
canvas.save();
scaleA = 1.1;
scaleB = 1.1;
canvas.scale(scaleA, scaleB);
canvas.restore();
the issue is even when i scale the Y coordinates move down, so i try to translate or reduce y coordinates but i still issue. any one knows how to properly scale a drawing canvas?
i tried like this:
canvas.save();
scaleA = 1.1;
scaleB = 1.1;
canvas.translate(scaleA, -scaleB);
canvas.scale(scaleA, scaleB);
canvas.restore();
You have to set the center of your image, if your image center is equal to the canvas(view) center
canvas.scale(sx, sy, canvas.getWidth() / 2, canvas.getHeight() / 2);
Or else, change the last two params to whatever center you want it to be, you don't need to translate
I can't just seem to figure it out. I am trying to draw a segmented circle (what looks like circle inside a circle). However I want the segments to have specific colors and to be transparent inside the smaller circle. Preferably , I would like to make the color of the segmented lines different than the circle
Here are the solutions I had in mind:
1- Draw arc with fill color for the bigger circle and draw a circle for the small circle. 2 problems with this. First one is that the inner circle area is no longer transparent as it takes the color from the bigger one. Second problem is that the segmentation lines of the outer circle is going all the way to the center (not only to the inner circle perimeter)
2) Draw arcs for the bigger outer circle and draw circle for the inner circle. Set it to be color filled but don't show strokes. Then draw another outer circle on top with no fill just to show strokes. And then draw lines between the inner and outer circle using the calculations ( angle and radius) to determine where the lines are... Very convoluted solution, there has to be another way. Even with this solution, still have problem with the color showing in the center but maybe playing with gradient can help.
I read so much on SO but I couldn't figure the right answer as many answers would remove the control of circle parameters
HEELP!!!
#Override
public void draw(Canvas canvas) {
float size = Math.min(getWidth(),getHeight());
paint.setStrokeWidth(size/4);
paint.setStyle(Paint.Style.STROKE);
final RectF oval = new RectF(0, 0, getWidth(), getHeight());
oval.inset(size/8,size/8);
paint.setColor(Color.RED);
Path redPath = new Path();
redPath.arcTo(oval, 0, 120, true);
canvas.drawPath(redPath, paint);
paint.setColor(Color.GREEN);
Path greenPath = new Path();
greenPath.arcTo(oval, 120, 120, true);
canvas.drawPath(greenPath, paint);
paint.setColor(Color.BLUE);
Path bluePath = new Path();
bluePath.arcTo(oval, 240, 120, true);
canvas.drawPath(bluePath, paint);
paint.setStrokeWidth(2);
paint.setColor(0xff000000);
canvas.save();
for(int i=0;i<360;i+=40){
canvas.rotate(40,size/2,size/2);
canvas.drawLine(size*3/4,size/2,size,size/2,paint);
}
canvas.restore();
final RectF ovalOuter = new RectF(0, 0, getWidth(), getHeight());
ovalOuter.inset(1,1);
canvas.drawOval(ovalOuter,paint);
final RectF ovalInner = new RectF(size/4, size/4, size*3/4,size*3/4);
canvas.drawOval(ovalInner,paint);
}
I'm drawing arcs using the Path class and strokes. Style.STROKE gives arcs without filling. Stroke width is set to size/4 which is a quarter of the view. Half of that stroke width goes outside and the second half goes inside, like this:
xxxxxxxx outer border of the arc of width 5
xxxxxxxx
------------ stroke
xxxxxxxx
xxxxxxxx inner border of the arc
That's why I'm using insets - I need to offset the stroke a bit in order to fit it in the view. Without insets the arcs are cut by all four sides of the view.
And why canvas rotation? Because it's easier to rotate the canvas with built-in methods than calculate lines manually. Rotation uses trigonometric functions and quickly becomes quite complex, hard to read and error prone. Basically I'm rotating the paper and drawing straight lines.
I want to draw on canvas month's text vertical along screen height.
Paint init:
this.paint = new Paint();
this.paint.setAntiAlias(true);
this.paint.setDither(true);
this.paint.setSubpixelText(true);
this.paint.setColor(color_text_dark);
this.paint.setTextAlign(Align.RIGHT);
Drawing:
// Set the scale to the widest month
float scale = getHeight() / this.max_month_width;
String month_string = FULL_MONTH_NAME_FORMATTER.
format(active_month_calendar.getTime());
canvas.save();
canvas.translate(getWidth(), 0);
canvas.rotate(-90);
canvas.scale(scale, scale);
canvas.drawText(month_string, 0, 0, this.paint);
canvas.restore();
Result looks good on hdpi screen, but very ugly and pixelated on xhdpi one.
I did more test on various devices, and understood what result depends on Android version, not screen density and resolution.
Code works fine on 2.x platform, but doesn't work on 4.0.3+. Suppose, Android draw implementation was changed here.
Full code you can see here.
hdpi version 2.3.5 (also tested 2.2)
xhdpi version 4.2 (also tested 4.1, 4.0.3)
Trying different variations for paint antialias, subpixel text has no effect. How can I fix this issue?
The problem is that you're drawing text at one size and scaling the result up. Once you've determined how wide you want the text to be, you should use calls to Paint.measureText(), adjusting the size via Paint.setTextSize() accordingly. Once it measures correctly, then you do your call to Canvas.drawText().
An alternative would be to not measure the text at all and just immediately call:
paint.setTextSize(paint.getSize() * scale)
There's no guarantee the text will fit in this case, though.
None of your other transform calls should result in interpolation, so it should give you very sharp lines.
Edit
Here is a code sample and comparison screenshot:
canvas.save();
canvas.scale(10, 10);
canvas.drawText("Hello", 0, 10, mTextPaint);
canvas.restore();
float textSize = mTextPaint.getTextSize();
mTextPaint.setTextSize(textSize * 10);
canvas.drawText("Hello", 0, 300, mTextPaint);
mTextPaint.setTextSize(textSize);
I don't have enough reputation to comment on Krylez's excellent answer, but I'd like to reply to mcfly soft's comment/question about paths.
The idea is the same for paths as text. Instead of scaling and translating the canvas a path is drawn on, put the same scaling and translation into a matrix and pass that to Path.transform:
// instead of this:
canvas.scale(sX, sY);
canvas.translate(trX, trY);
canvas.drawPath(path);
// do this:
matrix.postScale(sX, sY);
matrix.postTranslate(trX, trY);
path.transform(matrix);
canvas.drawPath(path);
I'm trying to draw a simple Rect on a Canvas that is at the X coordinate of 360, and the Y coordinate of 0. I can draw my Rect if I make the X coordinate to 0, but when I make it 360, the square becomes distorted and becomes a rectangular shape rather than a square anymore. My screen size is 640px wide, so there should be no problem here. I can draw Bitmaps with the same specifications and it will draw normally. Why is it that Rects don't draw correctly? Is it somehow that the X coordinate is only in DP rather than PX? Then why does that affect the actual size of the Rect? I'm really confused.
Rect square6 = new Rect();
square6.set(360, 0, 60, 60);
You should read the reference to the Rect in Android, The set func of Rect is public void set (int left, int top, int right, int bottom), you set your rect start from (360, 0) and ends at (60, 60), you should change the parmas to (360, 0, 420, 60). It will work.
If I use this:
mCamera.rotateY(45);
mCamera.getMatrix(mMatrix);
mMatrix.preTranslate(-pivotX, -pivotY);
mMatrix.postTranslate(pivotX + centerX, pivotY + centerY);
And do:
canvas.drawBitmap(bitmap, mMatrix, null);
Then the drawn picture will be taller and slimmer and the matrix will be nicely applied to the whole picture. Now, is there any way to calculate the rotated size? I want to fit the image by scaling it and now when I rotate it some of the top and bottom is clipped because of the parent's constraints. Thanks!
EDIT:
What I am going to do is spin the image and the range for rotateY will be from 0 to 90.
Well, you could easily let the matrix map the corners of your bitmap and then calculate the bounds, as the mapped corners will be the max / min for x and y coordinate. Maybe you can do it without too many if clauses :)
Edit:
Check out
RectF r = new RectF(/*your bitmap's corners*/);
matrix.mapRect(r);
That way you should get r's new size.
If you stick to 45° then Pythagoras is the key