I have a button which is drawn using canvas onDraw method. The button itself may will change size depending on device, but I want the text I'm drawing inside to remain consistent, even with different screen size or font size user may have set in settings. That is why I'm doing it in pixels.
#Override
public void onDraw(Canvas canvas) {
// 1. draw background
paint.setStyle(Paint.Style.FILL);
paint.setColor(colorBg);
canvas.drawRect(padding, padding, w-padding, h-padding, paint);
// 2. draw border
paint.setStyle(Paint.Style.STROKE);
paint.setColor(colorBorder);
canvas.drawRect(padding, padding, w-padding, h-padding, paint);
// 3. draw text
int fontSizeTextNew = canvas.getHeight() / 100 * 19;
int fontSizePaddingNew = canvas.getHeight() / 100 * 19;
textPaint.setTextSize(fontSizeTextNew);
textPaint.setShader(blackShader);
textPaint.setTypeface(Typeface.DEFAULT);
textPaint.getTextBounds(
prefTitle, // text
0, // start
prefTitle.length(), // end
rectangle // bounds
);
canvas.drawText(
prefTitle,
canvas.getWidth()/2,
Math.abs(rectangle.height()) + padding + fontSizePaddingNew,
textPaint
);
// 4. draw icon
int fontSizeIconNew = canvas.getHeight() / 100 * 55;
String str = prefIcon;
textPaint.setTypeface(awesomeFont);
textPaint.setTextSize(fontSizeIconNew);
textPaint.setShader(yellowShader);
// center for the text
// https://stackoverflow.com/questions/11120392/android-center-text-on-canvas
int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
canvas.drawText(
str,
canvas.getWidth()/2,
Math.abs(yPos) + fontSizeIconPadding,
textPaint
);
}
This 19% looks nice right now but it will look different on variouse screens. What is your approach to this problem? how you would solvethis problem?
Button1 This is how it may look
Related
First I will explain what I am trying to achieve. I am trying to achieve cropping functionality. For that, I am drawing one rectangle on canvas and then trying to draw heart inside rectangle. So If user minimize/maximize rectangle heart will also minimize/maximize.
Here is my code.
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mIsInitialized) {
setMatrix();
Matrix localMatrix1 = new Matrix();
localMatrix1.postConcat(this.mMatrix);
Bitmap bm = getBitmap();
if (bm != null) {
canvas.drawBitmap(bm, localMatrix1, mPaintBitmap);
// draw edit frame
drawEditFrame(canvas);
}
}
}
private void drawEditFrame(Canvas canvas) {
mPaintTransparent.setFilterBitmap(true);
mPaintTransparent.setColor(mOverlayColor);
mPaintTransparent.setStyle(Paint.Style.FILL);
Path path = new Path();
path.addRect(mImageRect.left, mImageRect.top, mImageRect.right, mImageRect.bottom,
Path.Direction.CW);
drawHeart(mFrameRect.centerX(), mFrameRect.centerY(), path);
canvas.drawPath(path, mPaintTransparent);
}
private Path drawHeart(float width, float height, Path path) {
// Starting point
path.moveTo(width / 2, height / 5);
// Upper left path
path.cubicTo(5 * width / 14, 0,
0, height / 15,
width / 28, 2 * height / 5);
// Lower left path
path.cubicTo(width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height);
// Lower right path
path.cubicTo(4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5);
// Upper right path
path.cubicTo(width, height / 15,
9 * width / 14, 0,
width / 2, height / 5);
return path;
}
private void setMatrix() {
mMatrix.reset();
mMatrix.setTranslate(mCenter.x - mImgWidth * 0.5f, mCenter.y - mImgHeight * 0.5f);
mMatrix.postScale(mScale, mScale, mCenter.x, mCenter.y);
mMatrix.postRotate(mAngle, mCenter.x, mCenter.y);
}
But heart is sticking at top left corner and not moving or minimizing/maximizing as per rectangle.
Here is current image for reference.
Please provide me hint or any reference.
EDIT I am able to draw circle inside rectangle which minimize/maximize as per rectangle size and move as per rectangle move. But I am not able to do same with custom heart. Here is code for circle.
path.addCircle((mFrameRect.left + mFrameRect.right) / 2,
(mFrameRect.top + mFrameRect.bottom) / 2,
(mFrameRect.right - mFrameRect.left) / 2, Path.Direction.CCW);
Here is image in which I am drawing circle in rectangle which I want to achieve same with heart too.
The implementation be like you should retake the whole bitmap size(height, width) before resizing then max/min the size of that bitmap.
I have view in which, I want to display a heart that is filled based on percentage shown in middle of heart.
I tried canvas, was able to draw heart but could not partial fill, used cliprect,etc but could not achieve this, please see Image
Now if its 30 %, then only 30% area from bottom should be filled with redcolor rest should be white, also the color outside of heart is blue which needs to be same way always as shown in image.
int percentage = 85;
int w = 100;
int h = 100;
Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
Path path = new Path();
// Fill the canvas with background color
canvas.drawColor(Color.BLUE);
paint.setShader(null);
float width = 100.00f;
float height =100.00f;
// Starting point
path.moveTo(width / 2, height / 5);
// Upper left path
path.cubicTo(5 * width / 14, 0,
0, height / 15,
width / 28, 2 * height / 5);
// Lower left path
path.cubicTo(width / 14, 2 * height / 3,
3 * width / 7, 5 * height / 6,
width / 2, height);
// Lower right path
path.cubicTo(4 * width / 7, 5 * height / 6,
13 * width / 14, 2 * height / 3,
27 * width / 28, 2 * height / 5);
// Upper right path
path.cubicTo(width, height / 15,
9 * width / 14, 0,
width / 2, height / 5);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
// draw text percentage
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(12);
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
//((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.
canvas.drawText(percentage+" % ", xPos, yPos, textPaint);
int heightOfClip = 100 - percentage;
//clip
canvas.clipRect(0,0,100,heightOfClip, Region.Op.XOR);
// draw heart and color it
canvas.drawPath(path, paint);
// draw text percentage
canvas.drawText(percentage+"%", xPos, yPos, textPaint);
mSampleIv.setImageBitmap(bitmap);
I want to draw texts on the sides of a circle and another one below it. I edited the code in this answer but the problem is that the circle and arc are taking the whole space of the rect, which makes no space for the text to be drawn.
Here is my code
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// getHeight() is not reliable, use getMeasuredHeight() on first run:
// Note: mRect will also be null after a configuration change,
// so in this case the new measured height and width values will be used:
if (mRect == null) {
// take the minimum of width and height here to be on he safe side:
centerX = getMeasuredWidth() / 2;
centerY = getMeasuredHeight() / 2;
radius = Math.min(centerX, centerY);
// mRect will define the drawing space for drawArc()
// We have to take into account the STROKE_WIDTH with drawArc() as well as drawCircle():
// circles as well as arcs are drawn 50% outside of the bounds defined by the radius (radius for arcs is calculated from the rectangle mRect).
// So if mRect is too large, the lines will not fit into the View
int startTop = STROKE_WIDTH / 2;
int startLeft = startTop;
int endBottom = 2 * radius - startTop;
int endRight = endBottom;
mRect = new RectF(startTop, startLeft, endRight, endBottom);
}
// subtract half the stroke width from radius so the blue circle fits inside the View
canvas.drawCircle(centerX, centerY, radius - STROKE_WIDTH / 2, mBasePaint);
// Or draw arc from degree 192 to degree 90 like this ( 258 = (360 - 192) + 90:
// canvas.drawArc(mRect, 192, 258, false, mBasePaint);
// draw an arc from 90 degrees to 192 degrees (102 = 192 - 90)
// Note that these degrees are not like mathematical degrees:
// they are mirrored along the y-axis and so incremented clockwise (zero degrees is always on the right hand side of the x-axis)
canvas.drawArc(mRect, 270, mTemp * 6, false, mDegreesPaint); // Each degree in the temp scale = 6 degrees on circle
canvas.drawArc(mRect, 270 + mSeparator * 6, 3, false, mSeparatorPaint); // The separator size = 3 degrees
// subtract stroke width from radius so the white circle does not cover the blue circle/ arc
canvas.drawCircle(centerX, centerY, radius - STROKE_WIDTH, mCenterPaint);
drawCenter(canvas, mTextPaint, mTemp + "°");
canvas.drawText("Temp 1", mRect.centerX(), radius * 2, mTextPaint);
}
This code produces what I need as an arc and circles, but I'm not able to draw degrees on the circle sides and a text below it
Any help??
I have created a custom EditText class which draws line numbers next on the left of every line. This works fine however I also want to set background of the line numbers to grey and achieve something like this:
In onDraw method where I draw the numbers I tried to draw really thick line but it always gets drawn over the line numbers no matter where I put it, before the call the draws the line numbers or after. Here is my code
protected void onDraw(Canvas canvas) {
int baseline = getBaseline();
for (int i = 0; i < getLineCount(); i++) {
//line still gets drawn over the text
canvas.drawText("" + (i + 1), rect.left, baseline, paint);
canvas.drawLine(rect.left,baseline,rect.right,rect.top,fill);
canvas.drawText("" + (i + 1), rect.left, baseline, paint);
baseline += getLineHeight();
}
super.onDraw(canvas);
}
Any suggestions about how to make the line appear in the background?
Thanks
Try to draw a line at which the width of the line number. before the loop:
Paint linePaint = new Paint(getPaint()); // copy original Paint
linePaint.setARGB(255, 200, 200, 200); // some grey color
String strCount = String.valueOf(getLineCount());
float[] symbolWidths = new float[strCount.length()];
linePaint.getTextWidths(strCount, symbolWidths);
float strokeWidth = 0;
for (float width : symbolWidths)
strokeWidth += width;
strokeWidth = strokeWidth *2/*I dnt knw y*/ + strokeWidth;
linePaint.setStrokeWidth(strokeWidth);
setPadding((int)strokeWidth / 2, 0, 0, 0); // text padding
canvas.drawLine(rect.left, getLineHeight() * getLineCount(), rect.right, rect.top, linePaint);
Im using camera in my android app but I have to add text to save captured image (after capturing image app should ask to add text to save captured image). How can I do this ?
What I think you are trying to do is to save a note with the image.
You should create a directory in which you will save the image with say name "image****.jpg". In the same directory create a file with same name but with different extension on no extension at all. (like "image****.txt").
When you access the image file, open the note file seperately and process it.
Try this to write text to bitmap from camera...
private Bitmap writeTextBitmap(Bitmap bitmap,String text) {
Typeface tf = Typeface.create("Helvetica", Typeface.BOLD);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.WHITE);
paint.setTypeface(tf);
paint.setTextAlign(Align.CENTER);
paint.setTextSize(20);
Rect textRect = new Rect();
paint.getTextBounds(text, 0, text.length(), textRect);
Canvas canvas = new Canvas(bitmap);
//If the text is bigger than the canvas , reduce the font size
if(textRect.width() >= (canvas.getWidth() - 4)) //the padding on either sides is considered as 4, so as to appropriately fit in the text
paint.setTextSize(convertToPixels(mContext, 7)); //Scaling needs to be used for different dpi's
//Calculate the positions
int xPos = (canvas.getWidth() / 2) - 2; //-2 is for regulating the x position offset
//"- ((paint.descent() + paint.ascent()) / 2)" is the distance from the baseline to the center.
int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2)) ;
canvas.drawText(text, xPos, yPos, paint);
return bitmap;
}