I'm trying to draw a number inside of a circle and having issues with the centering on the text. The following is the xml I'm using to display the TextView
<RelativeLayout
android:id="@+id/label"
android:layout_width="72dip"
android:layout_height="72dip"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_margin="8dip" >
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/hole_background"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/hole"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="@android:color/white"
android:textSize="56sp"
android:textStyle="bold"
android:gravity="center"/>
</RelativeLayout>
The problem is it is just slightly more towards the bottom (by about 10 pixels on the device I tested). This is a screenshot from the view hierarchy viewer that shows what I'm talking about...
I've tried combining the views and using the background such as here, or the removing the font padding like suggested here but neither worked, the font padding ending up as seen below...
I am currently am using a negative margin to adjust it to look right but that doesn't seem like the correct way to do it. Does anyone have any ideas on how to make text centered without using negative margins that I have to manually check based upon the text size?
Thanks in advance
So based upon the comments of LairdPleng and 323go I ended up just creating a custom view. The following view will do the centering exactly based upon the height of the number being drawn...
public class Label extends View {
private static final int TEXT_SIZE = 56;
private String mText;
private float mCenterX;
private float mCenterY;
private float mRadius;
private Paint mCirclePaint;
private Paint mTextPaint;
private Rect mTextBounds;
public HoleLabel(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupCanvasComponents(context);
}
public HoleLabel(Context context, AttributeSet attrs) {
super(context, attrs);
setupCanvasComponents(context);
}
public HoleLabel(Context context) {
super(context);
setupCanvasComponents(context);
}
public void setText(String text) {
if (!StringUtils.equals(mText, text)) {
mText = text;
invalidate();
}
}
private void setupCanvasComponents(Context context) {
mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setColor(Color.BLACK);
mCirclePaint.setStyle(Paint.Style.FILL);
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/CustomFont.otf");
DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getMetrics(displayMetrics);
float scaledDensity = displayMetrics.scaledDensity;
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);
mTextPaint.setColor(Color.WHITE);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTextSize(TEXT_SIZE * scaledDensity);
mTextPaint.setTypeface(font);
mTextPaint.setTextAlign(Align.CENTER);
mTextBounds = new Rect();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2.0f;
mCenterY = h / 2.0f;
mRadius = w / 2.0f;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Draw the background
canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
// Draw the text
if (mText != null) {
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
canvas.drawText(mText, mCenterX, (mCenterY + mTextBounds.height() / 2), mTextPaint);
}
}
}
And in xml...
<com.example.widget.Label
android:id="@+id/label"
android:layout_width="72dip"
android:layout_height="72dip"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_margin="8dip" />
The result being...
I had a very specific use case so I don't know if it'll work well if with less rigid size specifications but it was the way to go for me.