Not able to center text in android canvas - android

I am using following code to write "g" inside a circle. "g" must be centered horizontally and vertically inside the circle. But I am not able to, where am I wrong ?
//sv is surfaceview which covers whole screen
sv.getHolder().addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
// surfaceview width
swidth=sv.getWidth();
sheight=sv.getHeight();
int height = sheight/3;
int mat = Math.min(height,swidth/2);
Paint paint= new Paint(Paint.ANTI_ALIAS_FLAG);
Paint paint1= new Paint(Paint.ANTI_ALIAS_FLAG);
Resources r = getResources();
paint.setColor(Color.CYAN);
paint1.setColor(Color.BLACK);
Canvas c = sv.getHolder().lockCanvas();
c.drawARGB(254, 254, 254, 254);
String t1="g";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4-bounds.width()/2, height+height/2+bounds.height()/2, paint1);
sv.getHolder().unlockCanvasAndPost(c);
}
This is the method used in above code.
private int determineMaxTextSize(String str, float maxWidth)
{
int size = 0;
Paint paint = new Paint();
do {
paint.setTextSize(++ size);
} while(paint.measureText(str) < maxWidth);
return size;
}
Here is what I get when I try 4 different texts.
EDIT:
After editing my code with this
paint1.setTextAlign(Align.CENTER);
String t1="N";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4, height+height/2+bounds.height()/2, paint1);
I get this outcome which is better
However, you can see "g" is still not aligned.

paint1.setTextAlign(Align.CENTER);
String t1="N";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4, height+height/2+bounds.height()/2, paint1);
Above code is the answer

Related

Update size of drawable in Android

I have TextDrawable class. When i call setText, the text is change but size of drawable not change follow text size. I want size of drawable auto change same as TextView. Thanks
This is my code
public class TextDrawable extends Drawable {
private Paint paint, strokePaint;
private String text;
private int instrinsicWidth, instrinsicHeight;
private float strokeWidth;
private Rect recBounds;
public TextDrawable(String text){
this.text = text;
strokeWidth = 4f;
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setTextSize(32f);
paint.setStyle(Paint.Style.FILL);
paint.setTextAlign(Paint.Align.CENTER);
instrinsicWidth = (int)(paint.measureText(text, 0, text.length()) + 4);
instrinsicHeight = paint.getFontMetricsInt(null) + 4;
strokePaint = new Paint();
strokePaint.setAntiAlias(true);
strokePaint.setColor(Color.GRAY);
strokePaint.setTextSize(32f);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(4f);
strokePaint.setTextAlign(Paint.Align.CENTER);
recBounds = new Rect();
paint.getTextBounds(text, 0, text.length(), recBounds);
}
public TextDrawable(String text, float textSize, int textColor, float strokeWidth, int strokeColor){
this.text = text;
this.strokeWidth = strokeWidth;
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(textColor);
paint.setTextSize(textSize);
paint.setStyle(Paint.Style.FILL);
paint.setTextAlign(Paint.Align.CENTER);
instrinsicWidth = (int)(paint.measureText(text, 0, text.length()) + strokeWidth);
instrinsicHeight = (int)(paint.getFontMetricsInt(null) + strokeWidth);
strokePaint = new Paint();
strokePaint.setAntiAlias(true);
strokePaint.setColor(strokeColor);
strokePaint.setTextSize(textSize);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(strokeWidth);
strokePaint.setTextAlign(Paint.Align.CENTER);
recBounds = new Rect();
paint.getTextBounds(text, 0, text.length(), recBounds);
//Log.d("htdu87", "rW-rH; w-h: " +recBounds.width()+"-"+recBounds.height()+";"+instrinsicWidth+"-"+instrinsicHeight);
}
public void setText(String text) {
this.text = text;
instrinsicWidth = (int)(paint.measureText(text, 0, text.length()) + strokeWidth);
instrinsicHeight = (int)(paint.getFontMetricsInt(null) + strokeWidth);
setBounds(0, 0, instrinsicWidth, instrinsicHeight);
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
Log.d("htdu87", "bouns: "+getBounds());
canvas.drawText(text, instrinsicWidth/2, instrinsicHeight-(instrinsicHeight-recBounds.height())-strokeWidth/2, strokePaint);
canvas.drawText(text, instrinsicWidth/2, instrinsicHeight-(instrinsicHeight-recBounds.height())-strokeWidth/2, paint);
}
#Override
public int getOpacity() {
// TODO Auto-generated method stub
return paint.getAlpha();
}
#Override
public void setAlpha(int alpha) {
// TODO Auto-generated method stub
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter filter) {
// TODO Auto-generated method stub
paint.setColorFilter(filter);
}
#Override
public int getIntrinsicHeight() {
// TODO Auto-generated method stub
return instrinsicHeight;
}
#Override
public int getIntrinsicWidth() {
// TODO Auto-generated method stub
return instrinsicWidth;
}
}
Problem is that default Views are not designed to catch changes in Drawable's size. So, you should assume that your Drawable is immutable and remove setText method at all - instead supply this parameter directly in constructor.
Basically, it leads to either recreating TextDrawable each time you want to change a text or reassigning it to respective View.

Sprite Sheet - new sprite being drawn on top of old sprites

Basically I tried to use a sprite sheet for animation. The aim is to count from 1 to 8 with 1 second interval. The numbers are image on a sprite sheet. The problem is once the number is being drawn to the canvas, it just won't go away. New image just drawn on top of the unwanted old image. Like this:
Is there a way to clear what has been drawn, so that new image can be drawn on a clean canvas?
DrawStripFrame Class:
public class DrawStripFrame extends SurfaceView implements Runnable{
/**variables declared here*/
public DrawStripFrame (Context context){
super (context);
this.context = context;
holder = getHolder();
}
public void setDrawStripFrame(Bitmap bitmap, int width, int height, int columns){
this.bitmap = bitmap;
this.width = width;
this.height = height;
this.columns = columns;
}
}
#Override
public void run(){
while(running){
if(!holder.getSurface().isValid())
continue;
Canvas canvas = holder.lockCanvas();
draw(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
public void draw (Canvas canvas){
update();
/**4 being no. of columns and 2 being no. of row*/
int u = (frame % 4)*(width/4);
int v = (frame / 4)*(height/2);
Rect src = new Rect(u,v,u+(width/4),v+(height/2));
Rect dst = new Rect (0,0, 100,100);
Paint paint = new Paint();
canvas.drawBitmap(bitmap, src, dst, paint);
}
public void resume() {
running = true;
gameloop = new Thread(this);
gameloop.start();
}
public void update (){
frame++;
if (frame>10)
frame = 0;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In your case you could just redraw the canvas with a color like this:
public void draw (Canvas canvas){
update();
// clearing canvas
canvas.drawColor(Color.BLUE); // whatever color you need it to be
/**4 being no. of columns and 2 being no. of row*/
int u = (frame % 4)*(width/4);
int v = (frame / 4)*(height/2);
Rect src = new Rect(u,v,u+(width/4),v+(height/2));
Rect dst = new Rect (0,0, 100,100);
Paint paint = new Paint();
canvas.drawBitmap(bitmap, src, dst, paint);
}

Trying to make bitmap Fade in and Out

Hi im trying to get my bitmap to fade in and out. The bitmap is being drawn to a canvas
on a surfaceview. I am also using a sprite class to draw sprites to my canvas:
public class sprite {
static int x, y;
static int xSpeed, ySpeed;
static int height, width;
static Bitmap b;
static CanvasView canView;
static Paint fadePaint;
public sprite(CanvasView canvasView, Bitmap xSpriteSheet) {
// TODO Auto-generated constructor stub
b = xSpriteSheet;
canView = canvasView;
fadePaint.setAlpha(100); //Heres where logcat gives me an error
// divide by 2 for rows in sprite sheet
//4 colums
height = b.getHeight();
width = b.getWidth();
x = 0; y = 0;
xSpeed = 5;
ySpeed = 0;
}
public static void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Rect src = new Rect(0, 0 , width, height);
Rect dst = new Rect(x, y, x+width, y+height);
update();
canvas.drawBitmap(b, src, dst, fadePaint);
}
private static void update() {
// TODO Auto-generated method stub
x += xSpeed;
}
Heres what my logcat gives me:
FATAL EXCEPTION: Thread-273
java.lang.NullPointerException
at com.mrsai.xsos.sprite.<init>(sprite.java:25)
at com.mrsai.xsos.Game$CanvasView.run(Game.java:101)
at java.lang.Thread.run(Thread.java:856)
It is because you did not initialize the Paint. Change this:
static Paint fadePaint;
To this:
static Paint fadePaint = new Paint();

Use of constant in Canvas.drawLine()

I have this code.
Only the first drawLine gets drawn and the rest 2 are not. Can anyone explain why the other two drawlines do not work in the present case?
They work if I replace "factor" with "1/2" in the drawLine() statements.
Thanks
public class RenderView extends View {
Paint paint;
private float factor = 1/2;
public RenderView(Context context) {
// TODO Auto-generated constructor stub
super(context);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected void onDraw(Canvas canvas) {
int screenWidth = canvas.getWidth();
int screenHeight = canvas.getHeight();
paint.setColor(Color.RED);
canvas.drawLine(0, 0, screenWidth, screenHeight, paint);
canvas.drawLine(factor*screenWidth, 0, factor*screenWidth, screenHeight, paint);
canvas.drawLine(0, factor*screenHeight, screenWidth, factor*screenHeight, paint);
invalidate();
}
}
1/2 is 0 (by integer division). Try 1f/2 or just 0.5f.
I think the problem is that 1/2 is integer division, and so 1/2 = 0. Try 0.5f instead.

How to make view react on click

I have created custom widget which inherits View.
<com.test.www.view.ElementView
android:id="#+id/surface1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_weight="1"
/
>
and
public class ElementView extends View {
private final int width=100;
private final int height=100;
private Paint paint=null;
private Canvas canvas=null;
public ElementView(Context context) {
super(context);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr) {
super(context, attr);
paint = new Paint();
}
public ElementView(Context context, AttributeSet attr, int defaultStyles) {
super(context, attr, defaultStyles);
paint = new Paint();
}
#Override
protected void onMeasure(int widthSpec, int heightSpec) {
int measuredWidth = MeasureSpec.getSize(widthSpec);
int measuredHeight = MeasureSpec.getSize(heightSpec);
setMeasuredDimension(this.width,this.height);
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas=canvas;
// get the size of your control based on last call to onMeasure
int height = getMeasuredHeight();
int width = getMeasuredWidth();
// Now create a paint brush to draw your widget
paint.setColor(Color.GREEN);
//define border
this.canvas.drawLine(0, 0, 0, 99, paint);
this.canvas.drawLine(0, 0, 99,0, paint);
this.canvas.drawLine(99, 0, 99, 99, paint);
this.canvas.drawLine(0, 99, 99,99, paint);
//define cells
this.canvas.drawLine(0,50,99,50,paint);
this.canvas.drawLine(30,0,30,50,paint);
//draw green rectangle
this.canvas.drawRect(new Rect(0,0,50,50),paint);
//draw some text
paint.setTextSize(8);
paint.setColor(Color.RED);
String displayText = "test";
Float textWidth = paint.measureText(displayText);
int px = width / 2;
int py = height / 2;
this.canvas.drawText(displayText, px - textWidth / 2, py, paint);
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
paint.setColor(Color.RED);
//change color of first cell
canvas.drawRect(new Rect(0,0,50,50),paint);
return super.dispatchTouchEvent(event);
}
}
Problem is that this ElementView doesn't react on click. I have override of dispatch event but it doesn't come in. Can anybody help me ? What to do to make this ElementView react on click ?
I would probably do something like this:
ElementView ev = (ElementView)findViewById(R.id.surface1);
ev.setOnClickListener(evOnClick);
public OnClickListener evOnClick = new OnClickListener() {
#Override
public void onClick(View v, int arg1) {
//DO ONCLICK STUFF
}
};
I'm not sure if you can actually put the onClick inside the view definition like you are trying to, but Id like if someone could show me how.

Categories

Resources