Reputation: 457
I have to place marker on map view and write a number on marker. I have done that, but text alignment varies in different resolution. bellow is the reference code
float xVal = (float) curScreenCoords.x; // Point curScreenCoords
float yVal = (float) curScreenCoords.y-20; // Point curScreenCoords
Bitmap bitmap = BitmapFactory.decodeResource ( context.getResources() , ( R.drawable.pin_number ) ) ;
canvas.drawBitmap(bitmap, xVal, yVal, getInnerPaint());
public Paint getInnerPaint() {
if (innerPaint == null) {
innerPaint = new Paint();
}
innerPaint.setARGB(255, 117, 161, 220); // blue
innerPaint.setAntiAlias(true);
innerPaint.setStyle(Style.FILL);
return innerPaint;
}
canvas.drawText(String.valueOf(10), xVal+20, yVal+22, getCountPaint()); // 10 is just for example, it can vary to one digit to two to three
public Paint getCountPaint() {
if (innerPaint == null) {
innerPaint = new Paint();
}
innerPaint.setARGB(255, 255, 255, 255);
innerPaint.setAntiAlias(true);
innerPaint.setStyle(Style.FILL);
innerPaint.setTextSize(12f);
innerPaint.setTextAlign(Align.CENTER);
return innerPaint;
}
everything works fine, excepting text alignment, this code works fine for 480*800 resolution. Text is perfectly center aligned in canvas. x, y position is perfect on image, but this does not look perfect on 320*480. x and y position of text looks different on this resolution. Can anyone please suggest me what exactly happens wrong? is there any fundamentals for doing the same on different sized devices? Thanks in advance.
Upvotes: 3
Views: 5763
Reputation: 3970
I had the same issue. I wanted to draw text inside bitmap - for clustering purpose on Google Maps. Actually it draws text on the CENTER of the bitmap.
Code written in Kotlin
fun createCircleBitmapWithTextInside(context: Context, @DrawableRes drawableId: Int, text: String = "POI"): Bitmap{
val scale = context.resources.displayMetrics.density
var bitmap = getBitmap(context, drawableId)//BitmapFactory.decodeResource(res, drawableId)
var bitmapConfig = bitmap.config ?: Bitmap.Config.ARGB_8888
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true)
val canvas = Canvas(bitmap)
val paint = Paint(ANTI_ALIAS_FLAG)
paint.color = ResourceUtils.getColor(context, R.color.white)
paint.textSize = (18 * scale)
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE)
paint.style = Paint.Style.FILL
paint.textAlign = Paint.Align.CENTER
val bound = Rect()
paint.getTextBounds(text, 0, text.length, bound)
val x = (canvas.width.toFloat() /2)
// x - point to the center of width
val y = canvas.height / 2 - (paint.descent() + paint.ascent()) / 2
/* Timber.d("bitmap.width:${canvas.width} \tbound.width:${bound.width()} \tx:$x")
Timber.d("bitmap.height:${canvas.height} \tbound.height:${bound.height()} \ty:$y")*/
canvas.drawText(text, x, y, paint)
return bitmap
}
Upvotes: 0
Reputation: 509
Hi I guess None of the answers given above are good enough so i post my answer try it out guys will work on all devices and is not complex at all
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//paint.setTextAlign(Align.CENTER);
paint.setColor(activity.getResources().getColor(R.color.white));
paint.setTextSize(30);
// draw text to the Canvas center
Rect boundsText = new Rect();
paint.getTextBounds(String.valueOf(cluster.getMarkerList().size()), 0,
String.valueOf(cluster.getMarkerList().size()).length(), boundsText);
int x = (bitmap.getWidth() - boundsText.width()) / 2;
int y = (bitmap.getHeight() + boundsText.height()) / 2;
canvas.drawText(String.valueOf(cluster.getMarkerList().size()), x, y, paint);
Upvotes: 5
Reputation: 1477
I think you can measure the width and height that the text would have once written in the canvas and then use it to center it. Something like:
String text = "whatever";
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
canvas.drawText(text, (canvas.getWidth() - bounds.width()) / 2, (canvas.getHeight() - bounds.height()) / 2, paint);
Upvotes: 5
Reputation: 11
Make sure you check hardware acceleration is turned off. On 4.1.2 and other devices (samsung Galaxy Tag 2.0) you get a Fatal Signal 11 error.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
This corrects the problem I was having with this code. The canvas.drawText was causing the error.
Upvotes: 1
Reputation: 6702
Your values curScreenCoords.y-20
and xVal+20, yVal+22
have constant pixel offset for all resolutions, but they should depend on device's pixel density like this:
xOffset = (int) (13.33f * context.getResources().getDisplayMetrics().density + 0.5f);
yOffset = (int) (14.67f * context.getResources().getDisplayMetrics().density + 0.5f);
canvas.drawText(String.valueOf(10), xVal + xOffset, yVal + yOffset, getCountPaint());
Upvotes: 2
Reputation: 13364
You can extend the Image class and override onDraw of it. As below
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.widget.ImageView;
/**
* @author amit
*
*/
public class CustomImageView extends ImageView {
private int notificationCount;
private Paint paint;
/**
* @param context
*/
public CustomImageView(Context context) {
super(context);
notificationCount = 0;
paint = new Paint();
paint.setColor(Color.RED);
ColorFilter cf = new ColorFilter();
paint.setColorFilter(cf);
paint.setStyle(Paint.Style.FILL);
paint.setFakeBoldText(true);
paint.setTextSize(15);
}
public synchronized void incrementNotification() {
notificationCount--;
this.invalidate();
}
public synchronized void decrementNotification() {
notificationCount++;
this.invalidate();
}
/**
* @return the notificationCount
*/
public synchronized int getNotificationCount() {
return notificationCount;
}
/**
* @param notificationCount
* the notificationCount to set
*/
public synchronized void setNotificationCount(int notificationCount) {
this.notificationCount = notificationCount;
this.invalidate();
}
/*
* (non-Javadoc)
*
* @see android.widget.ImageView#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
// System.out.println("OnDraw is called");
super.onDraw(canvas);
if (notificationCount == 0) {
return;
}
canvas.drawText(String.valueOf(notificationCount), 0, 0, paint);
}
}
Than You can call any of the following method
incrementNotification();
decrementNotification();
setNotification(int number);
Choose the color of your choice inside the constructor.. Good Luck!!
Upvotes: 0