Paint.getTextBounds() returns to big height - android

EDIT: The problem came from the emulator, the error did not appear on a real device :(
I'm trying to draw some text in a custom view and must there for measure it but the value of the Paint.getTextBounds() returns a height which is about 30% higher then the actual text which gives everything a quirky look.
I found this: Android Paint: .measureText() vs .getTextBounds() and tried to add the solution code to my own onDraw and saw that i the same measuring error as in my code. Here is a picture of the result:
Compare with:
The image is copied from Android Paint: .measureText() vs .getTextBounds()
Note the spacing above the text in the first picture. Any Ideas what might be causing this? Or are there alternative ways to measure height of a drawn string?
Here is the onDraw method:
#Override
public void onDraw(Canvas canvas){
// canvas.drawColor(color_Z1);
// r.set(0, 0, (int)(width*progress), height);
// paint.setColor(color_Z2);
//// canvas.drawRect(r, paint);
// textPaint.getTextBounds(text, 0, text.length(), r);
// canvas.drawRect(r, paint);
// canvas.drawText(text, 0, r.height(), textPaint);
final String s = "Hello. I'm some text!";
Paint p = new Paint();
Rect bounds = new Rect();
p.setTextSize(60);
p.getTextBounds(s, 0, s.length(), bounds);
float mt = p.measureText(s);
int bw = bounds.width();
Log.i("LCG", String.format(
"measureText %f, getTextBounds %d (%s)",
mt,
bw, bounds.toShortString())
);
bounds.offset(0, -bounds.top);
p.setStyle(Style.STROKE);
canvas.drawColor(0xff000080);
p.setColor(0xffff0000);
canvas.drawRect(bounds, p);
p.setColor(0xff00ff00);
canvas.drawText(s, 0, bounds.bottom, p);
}

i didnot test your code but i dont see any problems with Paint.getTextBounds():
public class TextBoundsTest extends View {
private Paint paint;
private Rect bounds;
public TextBoundsTest(Context context) {
super(context);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(32);
bounds = new Rect();
}
#Override
protected void onDraw(Canvas canvas) {
String text = "this is my text";
paint.getTextBounds(text, 0, text.length(), bounds);
Log.d(TAG, "onDraw " + bounds);
int x = (getWidth() - bounds.width()) / 2;
int y = 70;
paint.setColor(0xff008800);
bounds.offset(x, y);
canvas.drawRect(bounds, paint);
paint.setColor(0xffeeeeee);
canvas.drawText(text, x, y, paint);
}
}
add this in Activity.onCreate:
TextBoundsTest view = new TextBoundsTest(this);
setContentView(view);
the result is:

Related

Set letter spacing to drawTextOnPath

I am using following code to make a spinner wheel.
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
for (int i = 0; i < segmentColors.length; i ++)
{
drawDataSet(canvas, i);
}
canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth() - getWidth()/2 - dpToPx(5), mTransparentCirclePaint);
}
protected void drawDataSet(Canvas canvas, int position)
{
int color = segmentColors[position];
float mainArcAngle = ((float) 360/ (float)segmentColors.length);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
if ( position%2 == 0)
paint.setColor(color);
else
paint.setColor(Color.parseColor("#009f2f"));
RectF rect = new RectF(0, 0, getWidth(), getWidth());
canvas.drawArc(rect, (mainArcAngle * position), mainArcAngle, true, paint);
TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setAntiAlias(true);
mTextPaint.setTypeface(Typeface.MONOSPACE);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(18f);
Path path = new Path();
path.addArc(rect, (mainArcAngle * position), mainArcAngle);
//PathMeasure pm = new PathMeasure(path, false);
//DynamicLayout layout = new DynamicLayout(values[position], values[position], mTextPaint, (int) pm.getLength(), Layout.Alignment.ALIGN_CENTER, 1, 0, true);
//canvas.save();
//layout.draw(canvas);
//canvas.restore();
canvas.drawTextOnPath(values[position], path, 0 , getWidth() / 6 , mTextPaint );
}
The text that is written inside the arc is a bit compressed because of small spacing. How can I make it multiline or increase letter spacing?
Starting from API 21 you can use Paint#setLetterSpacing(float):
Set the paint's letter-spacing for text. The default value is 0. The value is in 'EM' units. Typical values for slight expansion will be around 0.05. Negative values tighten text.
You may also see how TextView#setLetterSpacing() is implemented.

Android - Any library for adding repost label to bitmap

I have been trying to make a photo sharing app, with the ability to add your image and name to the image. I have been messing with Canvas for the whole day, but couldn't get good results. I was able to draw the name and bitmap, but they didn't look so good.
That's why I am here asking about is there any library or piece of code that could help me in making something similar to [this][1]. I wasn't able to find any thing for it.
EDIT: Sorry for not adding my own code
Here is my code from my latest try
public void AddText(Position2D pos){
//Position2D is an enum having the 4 corners of the image
bmWorking= bmOriginal.copy(Bitmap.Config.ARGB_8888,true);
Canvas canvas = new Canvas(bmWorking);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
float width = (35f/100f) * bmWorking.getWidth();
float height = (width/16f) * 3;
textPaint.setTextSize(height - 4); //I wanted to have some space (margin) above and below the text
textPaint.setTextAlign(Paint.Align.LEFT);
float [] coords = getPositionCoords(pos, width, height); //getPositionCoords returns a float array with the Left,Top,Right,Bottom position calculated based on the width and height
canvas.drawRect(coords[0],coords[1], coords[2], coords[3],paint);
username = "Haider Ali Punjabi";
canvas.drawText(username, coords[0] ,coords[3], textPaint);
bitmapView.setImageBitmap(bmWorking);
}
Here is the result
UPDATE:
#pskink gave me this code
which works nicely
if you want to customize it, then instead of solid white rectangle (like in your original code) use a Drawable and the result could be something like this:
the code:
// for int gravity: see android.view.Gravity, like Gravity.LEFT, Gravity.BOTTOM, etc
// for example:
// Bitmap out = addText(this, in, "Haider Ali Punjabi", android.R.drawable.alert_light_frame, Gravity.BOTTOM, new Point(10, 10));
public Bitmap addText(Context ctx, Bitmap in, String text, int resId, int gravity, Point pad) {
if (pad == null) pad = new Point();
Bitmap out = in.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(out);
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.LEFT);
// textPaint.setTextSize(128);
Rect inBounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), inBounds);
float scale = out.getWidth() * 0.35f / inBounds.width();
Rect container = new Rect(0, 0, out.getWidth(), out.getHeight());
Rect outBounds = new Rect();
int w = (int) (inBounds.width() * scale);
int h = (int) (inBounds.height() * scale);
Gravity.apply(gravity, 2 * pad.x + w, 2 * pad.y + h, container, outBounds);
Drawable dr = ctx.getResources().getDrawable(resId);
Rect padding = new Rect();
dr.getPadding(padding);
dr.setBounds(outBounds.left - padding.left, outBounds.top - padding.top, outBounds.right + padding.right, outBounds.bottom + padding.bottom);
dr.draw(canvas);
Matrix matrix = new Matrix();
RectF src = new RectF(inBounds);
RectF dst = new RectF(outBounds);
dst.inset(pad.x, pad.y);
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
canvas.concat(matrix);
canvas.drawText(text, 0, 0, textPaint);
return out;
}

Android Custom View drawing got bad quality

I'm overriding View on Android to do some custom drawing, but the rendered view has not very good quality, especially the text. I have found a couple of solutions, but none worked for me. Attaching the code here. Thank you for any help.
#Override
protected void onDraw(Canvas canvas) {
int width = canvas.getWidth();
int height = canvas.getHeight();
Point a = new Point(0, 0);
Point b = new Point(width / 2, height);
Point c = new Point(width, 0);
Path trianglePath = new Path();
trianglePath.moveTo(a.x, a.y);
trianglePath.lineTo(b.x, b.y);
trianglePath.lineTo(c.x, c.y);
trianglePath.lineTo(a.x, a.y);
Paint paint = new Paint();
paint.setStrokeWidth(1);
paint.setColor(Color.parseColor("#7A7A7A"));
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
canvas.drawPath(trianglePath, paint);
Paint textPaint = new Paint();
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(height / 6);
textPaint.setTypeface(TypefaceUtils.getTypeface(getContext(), TypefaceUtils.AVAILABLE_FONTS.ROBOTO_THIN));
String receive = getContext().getString(R.string.receive_password).split("\n")[0];
String password = getContext().getString(R.string.receive_password).split("\n")[1];
Rect receiveBounds = new Rect();
Rect passwordBounds = new Rect();
textPaint.getTextBounds(receive, 0, receive.length(), receiveBounds);
textPaint.getTextBounds(password, 0, password.length(), passwordBounds);
canvas.drawText(
receive,
(width - receiveBounds.width()) / 2,
height / 3 - receiveBounds.height() + receiveBounds.height() / 5,
textPaint);
canvas.drawText(
password,
(width - passwordBounds.width()) / 2,
height / 3 + receiveBounds.height(),
textPaint);
canvas.scale(1, 1);
}
Try setting textpaint.setAntiAlias(true);

Draw text inside a filled rectangle using Canvas Android

How to draw a filled rectangle with specified bounds and inside that rectangle text to be drawn using Canvas Android ?? I tried
mPaint.setColor(Color.GREEN);
canvas.drawText(mText, x, y, mPaint);
mPaint.setColor(Color.BLACK);
canvas.drawRect(x, y, x + w, y + h, mPaint);
but text is not inside of that rectangle. Can any buddy tell me how to draw a rectangle surrounding specified text with consideration of text size ??
Here i have hardcoded x and y values. You can change them
mpaint= new Paint();
mpaint.setColor(Color.RED);
mpaint.setStyle(Style.FILL);
paint2= new Paint();
paint2.setColor(Color.GREEN);
paint2.setTextSize(50); //set text size
float w = paint2.measureText(s)/2;
float textSize = paint2.getTextSize();
#Override
protected void onDraw(Canvas canvas) {
paint2.setTextAlign(Paint.Align.CENTER);
canvas.drawRect(300-w, 300 - textsize, 300 + w, 300, mpaint);
canvas.drawText(s, 300, 300 ,paint2); //x=300,y=300
}
Edit :
Its bad a idea to call measureText in onDraw. You can do that outside of onDraw.
There is a video on also about performance and why you should avoid allocations in onDraw. https://www.youtube.com/watch?v=HAK5acHQ53E
Resulting snap shot
If you have to center the text inside de rect you have use this code
mpaint= new Paint();
mpaint.setColor(Color.RED);
mpaint.setStyle(Style.FILL);
paint2= new Paint();
paint2.setColor(Color.GREEN);
paint2.setTextSize(50); //set text size
float w = paint2.measureText(s)/2;
float textSize = paint2.getTextSize();
#Override
protected void onDraw(Canvas canvas) {
paint2.setTextAlign(Paint.Align.CENTER);
Rect rect = new Rect(300-w, 300 - textsize, 300 + w, 300);
canvas.drawRect(rect, mpaint);
canvas.drawText(s, rect.centerX(), rect.centerY() ,paint2); // center text inside rect
}
This might be very late for this particular query but I think many will find this answer useful. So, the problem with the Canvas for any CustomView is that, you can get the width for a particular text, but it's not that easy to get the height of the text. Also if you are using canvas.drawText(....) with simple Paint object, you can not draw multi line text. So, use the below code within your onDraw() method.
String displayText = "Hello World";
int mainTextPositionX = getWidth() / 2 ;
int mainTextPositionY = getHeight() / 2;
StaticLayout textStaticLayout;
TextPaint textPaint;
textPaint = new TextPaint();
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setColor(Color.BLUE);
textPaint.setAntiAlias(true);
textPaint.setTextSize(convertDpToPixel(30, context));
textPaint.setTextAlign(Paint.Align.CENTER);
highlightedRectPaint = new Paint();
highlightedRectPaint.setStrokeWidth(12);
highlightedRectPaint.setStyle(Paint.Style.STROKE);
highlightedRectPaint.setColor(Color.RED);
highlightedRectPaint.setAntiAlias(true);
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
textStaticLayout = StaticLayout
.Builder
.obtain(displayText, 0, displayText.length(), textPaint, (int) textPaint.measureText(displayText))
.build();
}else{
textStaticLayout = new StaticLayout(
displayText, textPaint, (int)textPaint.measureText(displayText), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
}
Rect highlightedTextBorderRect = new Rect();
highlightedTextBorderRect.top = mainTextPositionY-20;
highlightedTextBorderRect.left = mainTextPositionX-
((int)textPaint.measureText(displayText)/2)-20;
highlightedTextBorderRect.right = mainTextPositionX+
((int)textPaint.measureText(displayText)/2) + 20;
highlightedTextBorderRect.bottom = mainTextPositionY+
(int)textStaticLayout.getHeight()+20;
canvas.save();
canvas.translate(mainTextPositionX, mainTextPositionY);
textStaticLayout.draw(canvas);
canvas.restore();
canvas.drawRect(highlightedTextBorderRect,highlightedRectPaint);
just make sure that, you declare all the objects and variable outside of the draw() method. And this will draw a rectangle outline around the text with multi line support. If you want the rectangle to have a fill, then just use the highlightedRectPaint and change the setStyle(Paint.Style.FILL). Hope that helps.

Getting rendered text height, which is equivalent to rendered text width using paint.measureText

I have the following code to draw text.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(400);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setTextAlign(Align.LEFT);
paint.setStyle(Style.FILL);
String text = "698";
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();
int textHeight = bounds.height();
Bitmap originalBitmap = Bitmap.createBitmap(textWidth,
textHeight, Bitmap.Config.ARGB_8888);
Canvas singleUseCanvas = new Canvas(originalBitmap);
singleUseCanvas.drawColor(Color.BLUE);
singleUseCanvas.drawText(text, 0, textHeight, paint);
canvas.drawBitmap(originalBitmap, 0, 0, null);
}
I am getting undesired outcome, which its right and bottom sides are being cropped.
I avoid right side cropping, by using
float textWidth = paint.measureText(text);
Bitmap originalBitmap = Bitmap.createBitmap((int)(textWidth + 0.5),
textHeight, Bitmap.Config.ARGB_8888);
I am getting the following improvement
Yet. My bottom still being cropped. May I know what is the correct way to obtained rendered text height, which is analogy to rendered text width using paint.measureText?
I think i would be helpful to have a look at this post:
Android Paint: .measureText() vs .getTextBounds()
It have a good survey about sizing of rendered text and also text height which is your concern.

Categories

Resources