Tuesday, October 19, 2010

Custom view class and fonts handling for drawing text.

This post tells about how to write a custom view, and how to deal with fonts heights,and things needs to taken care while implementing custom view.



I was trying to implement a layout which looked exactly like above.

It was a horizontal linear layout, where the fonts were cropped in top & bottom by a bit of pixels.

I was going in the following approaches.

1 - A horizontal linear layout which had two textviews. And set the textSize attribute to '24px', which was the height of the parent horizontal layout.Expected the string will start from the top corner of the parent layout (0,0). But it dint happen.



<LinearLayout
android:layout_width="fill_parent"
android:layout_height="24px"
android:orientation="horizontal"
android:background="#ffffff">

<TextView android:id="@+id/urltextbox1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="90"/>

<TextView android:id="@+id/urltextbox2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="12:24p"/>

</LinearLayout>



And the output was like below.




Now the problem is , the fonts doesnt start exactly at the top - corner ( 0, 0) of the parent ViewGroup. TextView leaves some space and then started the text.

Later i tried to set diff parameters/attributes of textView thinking it will push the fonts above the size.
- android:height = "28px" --> Dint work. Still it left some padding in the top.

- android:includeFontPadding="false" --> Some hope. It reduced some space in the top.Removed the font padding at the top. ( Mainly this is left by TextView for languages like german where characters will have something like this. )



Then finally decided to write a custom view class and draw the text using canvas.

Here two things are important, fontSize/textSize and drawText- Y co-ordinate, Which tells canvas from where the text to start for drawing.


- Create paint object. Set textsize, padding, textcolor etc.
- Override onMeasure(), OnDraw() functions.
- onMeasure() - set the required width and height.


Some calculations are required to acheieve the fonts being cropped at the top & bottom.

Layout height = 24px.

We need to calculate 'y' value of drawText() api, which determines the text drawing starting point.



canvas.drawText(content,leftPadding, y, mPaint);

If we start at 0, then fonts wont be seen only.
If we start at 24, then fonts wont grow out below the layout's width. But it can grow on if we keep the textSize more than 24.

So it has to be 3 or 4 px > 24, may be 28px. So that font drawing will start from 28px and 4px height will be cropped in the bottom. And keeping proper textSize, it will grow beyond height of 24px and it will be cropped in top as well.




- setScaling() takes a float value, which multiplied by layout heights gives the starting point of font in drawText api.

- setText() will take the text.



 

package com.android.server.status;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.graphics.Typeface;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.Rect;

public class FontFitTextView extends View {

private String content="";
private Paint mPaint;
private float scaling;
private float textSize=0.0f;
private int leftPadding= 0;

public FontFitTextView(Context context) {
super(context);
init();
}

public FontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

private void init(){

mPaint = new Paint();
// set's the paint's colour
mPaint.setColor(Color.rgb(0x58, 0x58, 0x58));
// smooth's out the edges of what is being drawn
mPaint.setAntiAlias(true);

mPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
}

public void setScaling(float scale)
{
this.scaling = scale;
}

public void setText(String text)
{
this.content = text;
invalidate();
}
public void setTextSize(float size)
{
this.textSize = size;
}
public void setPadding(int left,int right,int top,int bottom)
{
this.leftPadding = left;
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{

int height = MeasureSpec.getSize(heightMeasureSpec);

if(textSize == 0.0f )
{
textSize = height + ((height* 50 ) / 100);
mPaint.setTextSize(textSize);
}
else
mPaint.setTextSize(textSize);

int width =(int) mPaint.measureText(content) + leftPadding;
setMeasuredDimension(width,height);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

float y = getHeight() * scaling;

if(textSize == 0.0f )
{
textSize = getHeight() + ((getHeight()* 50 ) / 100);
mPaint.setTextSize(textSize);
}
else
mPaint.setTextSize(textSize);

System.out.println(" y " + " " + y + " text size " + textSize+"padding "+ leftPadding);

canvas.drawText(content,leftPadding, y, mPaint);

}

}

2 comments:

  1. Replies
    1. @Interior Malang Jember Surabaya can you please tell me how the xml of text view looks like

      Delete