I am drawing a text on android canvas using the following piece of code
Rect rect = new Rect();
paint.getTextBounds(text, 0, text.length(), rect);
canvas.translate(xPosition + position.getX(), yPosition + position.getY());
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
canvas.drawRect(rect, paint);
paint.setStyle(Style.FILL);
paint.setColor(text_color);
canvas.translate(-(xPosition + position.getX()), -(yPosition + position.getY()));
canvas.rotate(getDegreesFromRadians(angle), xPosition + position.getX() + rect.exactCenterX(), yPosition + position.getY() + rect.exactCenterY());
canvas.drawText(text, xPosition + position.getX(), yPosition + position.getY(), paint);
This code takes care of the rotation of the text and it works fine. I am drawing a blue rectangle around the text using the above code. Now my problem is that the rectangle is not rotating along with the text. It still remains the same. Is there any way to rotate the rectangle drawn in android canvas?
please use
canvas.save();
canvas.rotate();
//stuff to draw that should be rotated
canvas.restore();
else you have to compensate for every rotation afterwards
I found my own answer. I used the following code
Rect rect = new Rect();
paint.setColor(text_color);
paint.setStyle(Style.FILL);
paint.getTextBounds(text, 0, text.length(), rect);
canvas.translate(xPosition + position.getX(), yPosition + position.getY());
canvas.translate(-(xPosition + position.getX()), -(yPosition + position.getY()));
canvas.rotate(getDegreesFromRadians(angle), xPosition + position.getX() + rect.exactCenterX(), yPosition + position.getY() + rect.exactCenterY());
canvas.drawText(text, xPosition + position.getX(), yPosition + position.getY(), paint);
paint.getTextBounds(text, 0, text.length(), rect);
canvas.translate(xPosition + position.getX(), yPosition + position.getY());
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(4);
rect = new Rect(rect.left - 10, rect.top - 10, rect.right + 10, rect.bottom + 10);
canvas.drawRect(rect, paint);
The thing is the whole canvas is being rotated for rotating the text. So i just need to draw the rectangle after the rotation of the canvas.
Related
I'am doing a simple app which displays compas rose + two arrows which represents current and mean wind direction.
What I want is to rotate compas rose + two arrows after they are drawed on canvas.
Here is my example:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//compass rose
canvas.drawBitmap(broza, crozax, crozay, null);
// Draw current wind arrow + rotate for currentwinddirection from json
matrix.reset();
matrix.setRotate(180 + (float) currentWindDirection, bkazalec.getWidth() / 2, bkazalec.getHeight() / 2);
matrix.postTranslate(ckazalecx, ckazalecy);
canvas.drawBitmap(bkazalec, matrix, mPaint);
//Draw mean wind arrow + rotate for meanwinddirection from json
matrix.reset();
matrix.setRotate(180 + (float) meanWindDirection, bkazalecmean.getWidth() / 2, bkazalecmean.getHeight() / 2);
matrix.postTranslate(mkazalecx, mkazalecy);
canvas.drawBitmap(bkazalecmean, matrix, mPaint);
//here I want to rotate canvas (compas rose + two arrows) for certain degree number which I obtain from sensor.
.
.
//after this I must "draw" some text for certain datas
canvas.drawText(getResources().getString(R.string.pod_smer_vetra) + getCurrentWindDirection() + "°", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_hitrost_vetra) + getCurrentWindSpeed() + " m/s", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_povp_smer_vetra) + getMeanWindDirection() + "°", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_pov_hitrost_vetra) + getMeanWindSpeed() + " m/s", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_beaufort) + getMeanWindBeaufort(), x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_temp_povrsina_voda) + getTemperatureSeaSurface() + "°C", x, y, mPaint);
y += mPaint.getFontSpacing();
canvas.drawText(getResources().getString(R.string.pod_temp_zraka) + getTemperatureAir() + "°C", x, y, mPaint);
}
int saveCount = canvas.save(); // save canvas state
try { // just for case if some exceptions
canvas.rotate(angle, centerX, centerY);
if (needScale) canvas.scale(scaleX, scaleY, centerX, centerY);
// draw here what you want
} finally {
canvas.restoreToCount(saveCount); // restore previous state, further draw is unrotated
}
I am trying to create a jigsaw puzzle game, and I would like to know of alternative ways of creating puzzle pieces without using mask. Currently I have jigsaw pieces by taking a full image, breaking that image up into four pieces (lets say the puzzle is 2x2) and then storing and applying a mask to each piece. It looks like the below
// create standard puzzle pieces
arryPieceEndPos = new int[mCols][mRows];
arryPieceImg = new Bitmap[mCols * mRows];
arryIsPieceLocked = new boolean[mCols * mRows];
int pos = 0;
for (int c = 0; c < mCols; c++) {
for (int r = 0; r < mRows; r++) {
arryPieceImg[pos] = Bitmap.createBitmap(mBitmap,
c * mPieceWidth, r * mPieceHeight,
mPieceWidth, mPieceHeight);
arryIsPieceLocked[pos] = false;
arryPieceEndPos[c][r] = pos;
pos++;
}
}
I then use a helper method to apply a mask to each piece
private Bitmap maskMethod(Bitmap bmpOriginal, Bitmap bmpMask) {
// adjust mask bitmap if size is not the size of the puzzle piece
if (bmpMask.getHeight() != mPieceHeight ||
bmpMask.getWidth() != mPieceWidth) {
Log.e("TEST", "Resize Error :: H (mask): " + bmpMask.getHeight() + " // W (mask): " +
bmpMask.getWidth());
Log.d("TEST", "Resize Error :: H (norm): " + mPieceHeight + " // W (norm): " +
mPieceWidth);
}
Canvas canvas = new Canvas();
Bitmap combine = Bitmap.createBitmap(bmpOriginal.getWidth(), bmpOriginal.getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(combine);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.drawBitmap(bmpOriginal, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(bmpMask, 0, 0, paint);
paint.setXfermode(null);
return combine;
}
I saw this post > http://java.dzone.com/news/connect-pictures-android for connecting pieces together, however, this does not go over generating pieces programmatically without masks. Can anyone provide code examples of how this can be accomplished? The only clue I have is that I should be using Path, however, I am still not sure how. Thanks in advance!
A puzzle piece is a pretty complex view to create, but I can help you understand how to use path. Here is the link to the developer website: http://developer.android.com/reference/android/graphics/Path.html
Look into this link. I made a small thing for you to start. The one thing you need to figure out is how to cut a small circle out of the path, which I wouldn't know. I think you have to look into clipping to have your path follow a circle (you could also do clipping for creating the circle outside the piece, I just haven't done clipping before).
private Bitmap getPuzzleBitmap(Bitmap bitmap)
{
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
calculatePuzzlePath(bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawPath(puzzlePath, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
private void calculatePuzzlePath(int width, int height)
{
float radius = (height / 2) - 5;
float smallRadius = radius / 3;
radius -= smallRadius * 2;
float centerX = width/2;
float centerY = height/2;
puzzlePath = new Path();
// Bottom right
puzzlePath.moveTo(centerX + radius, centerY + radius);
// Top right
puzzlePath.lineTo(centerX + radius, centerY - radius);
// Center top
puzzlePath.lineTo(centerX, centerY - radius);
// Add outside circle to center top
puzzlePath.addCircle(centerX, centerY - radius - ((radius / 3) / 2), radius / 3, Path.Direction.CCW);
// Top left
puzzlePath.lineTo(centerX - radius, centerY - radius);
// Bottom left
puzzlePath.lineTo(centerX - radius, centerY + radius);
//Bottom right
puzzlePath.lineTo(centerX + radius, centerY + radius);
}
I hope this is sufficient to get started with this.
Good luck!
I have a small question. I'm painting some RectFs on my canvas, but nothing happened.
I paint one filled RectF and another stroked RectF => filled background with a border.
For the first "field" everything is ok, but not for the second "field" (rect2).
The positions are checked. The last text is printed in that RectF (rect2) where the rect is not painted.
I uploaded an image on my FTP server. For the description of my problem it might be easier to understand.
Here is my code. I think it is a logical error?
// Fill rect
rect.set(fPosition, fPositionY, pts[2] - 10, fRectHeight);
paint.setColor(Color.GREEN);
paint.setStyle(android.graphics.Paint.Style.FILL);
paint.setStrokeWidth(0);
canvas.drawRoundRect(rect, 10, 10, paint);
// Border
paint.setColor(Color.BLACK);
paint.setStyle(android.graphics.Paint.Style.STROKE);
paint.setStrokeWidth(3);
canvas.drawRoundRect(rect, 10, 10, paint);
// Text
float fTextSize = fRectHeight - 40;
TextPaint textPaint = new TextPaint();
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(fTextSize);
float textHeight = textPaint.descent() - textPaint.ascent();
float textOffset = (textHeight / 2) - textPaint.descent();
canvas.drawText(dataStrings.getGewicht(), rect.centerX(), rect.centerY() + textOffset, textPaint);
// Leistung pro Stunde
rect2 = new RectF();
paint = new android.graphics.Paint();
fPositionY = fPositionY + fRectHeight + 50;
float fRectWidth = pts[2] / 2;
fRectHeight = (float) (pts[17] / 5);
// Fill rect
rect2.set(fPosition, fPositionY, fRectWidth, fRectHeight);
paint.setColor(Color.YELLOW);
paint.setStyle(android.graphics.Paint.Style.FILL);
paint.setStrokeWidth(0);
canvas.drawRoundRect(rect2, 10, 10, paint);
// Border
paint.setColor(Color.BLACK);
paint.setStyle(android.graphics.Paint.Style.STROKE);
paint.setStrokeWidth(3);
canvas.drawRoundRect(rect2, 10, 10, paint);
// Text
fTextSize = fRectHeight - 40;
textPaint = new TextPaint();
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(fTextSize);
textHeight = textPaint.descent() - textPaint.ascent();
textOffset = (textHeight / 2) - textPaint.descent();
canvas.drawText(dataStrings.getLeistung(), rect2.centerX(), rect2.centerY() + textOffset, textPaint);
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);
I'm using a Custom View where I created a Circle:
canvas.drawCircle(width/2, width/2, radius, paint1);
Now, I want to empty the circle from inside, something like a ring.
Drawing another smaller white circle will raise another problem. I'm planning to make my view listen to user clicks. I want to listen to the clicks on the ring only!
Is there a way to exclude some part of the canvas?
In order to draw a ring (i.e., a circle that is NOT filled in but just has a border, with the area inside transparent) do this:
Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
myPaint.setStyle(Paint.Style.STROKE);
int strokeWidth=4; // or whatever
myPaint.setStrokeWidth(strokeWidth);
myPaint.setColor(0xffff0000); //color.RED
float radius=(float) (0.5*(w+h)*0.5);
canvas.drawCircle((float)0.5*w, (float)0.5*h, radius, myPaint);
The call to drawCircle can also be replaced by drawArc like the code below. Either approach will work. The secret sauce is to set the paint style to Paint.Style.STROKE.
RectF oval = new RectF(w/2 - radius, w/2 - radius, w/2 + radius, w/2 + radius);
canvas.drawArc(oval, 0, 360, false, myPaint);
To draw a ring, use drawArc :
RectF oval = new RectF(width/2 - radius, width/2 - radius, width/2 + radius, width/2 + radius);
canvas.drawArc(oval, 0, 360, false, paint1);
I worked around the problem by drawing an inner white circle and filtering the clicks based on the two radius lengths I had.
So, you can't draw an empty circle but you can make a circle to behave like an empty one.
Thanks.
this solution works:
Paint paintPath;
int circleRadius = (int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources()
.getDisplayMetrics());
paintPath = new Paint();
paintPath.setStrokeWidth(circleRadius);
paintPath.setColor(Color.WHITE);
paintPath.setStyle(Paint.Style.FILL_AND_STROKE);
paintPath.setAntiAlias(true);
paintPath.setPathEffect(null);
paintPath.setRasterizer(null);
inside on draw
RectF rectF = new RectF(centerx - radius, centery - radius,
centerx + radius, centery + radius);
Path myPath = new Path();
for (int i = 0; i <= 360; i += 1)
{
myPath.addArc(rectF, i, 1);
}
canvas.drawPath(myPath, paintPath);
More short way:
draw = function() {
ctx.globalCompositeOperation = "lighter";
ctx.beginPath();
// ctx.fillStyle = "green";
ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
// ctx.fill();
ctx.strokeStyle = "yellow";
ctx.stroke();
ctx.closePath();
}