How to use a custom typeface in a widget?
This renders the font to a bitmap, and then assigns the bitmap to an ImageView.
public static RemoteViews buildUpdate(Context context)
{
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
Bitmap myBitmap = Bitmap.createBitmap(100, 50, Bitmap.Config.ARGB_4444);
Canvas myCanvas = new Canvas(myBitmap);
Paint paint = new Paint();
Typeface clock = Typeface.createFromAsset(context.getAssets(),"Clockopia.ttf");
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setTypeface(clock);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
paint.setTextSize(15);
myCanvas.drawText("Test", 0, 20, paint);
views.setImageViewBitmap(R.id.TimeView, myBitmap);
return views;
}
What is needed is to render the font onto a canvas, and then pass it on to a bitmap and assign that to an ImageView. Like so:
public Bitmap buildUpdate(String time)
{
Bitmap myBitmap = Bitmap.createBitmap(160, 84, Bitmap.Config.ARGB_4444);
Canvas myCanvas = new Canvas(myBitmap);
Paint paint = new Paint();
Typeface clock = Typeface.createFromAsset(this.getAssets(),"Clockopia.ttf");
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setTypeface(clock);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
paint.setTextSize(65);
paint.setTextAlign(Align.CENTER);
myCanvas.drawText(time, 80, 60, paint);
return myBitmap;
}
That's the part doing the font to image thingie, and this is how to use it:
String time = (String) DateFormat.format(mTimeFormat, mCalendar);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.main);
views.setImageViewBitmap(R.id.TimeView, buildUpdate(time));
As you might notice, this code just shows the current time in the imageview, but it can easily be adjusted to whatever needs.
Edit:
ARGB_4444 is deprecated for ARGB_8888 as stated in the documentation
This field was deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead.
I changed a little about measure size, so the bitmap will support different fontsize. It just support single line text.
public static Bitmap getFontBitmap(Context context, String text, int color, float fontSizeSP) {
int fontSizePX = convertDiptoPix(context, fontSizeSP);
int pad = (fontSizePX / 9);
Paint paint = new Paint();
Typeface typeface = Typeface.createFromAsset(context.getAssets(), "Fonts/Roboto-Regular.ttf");
paint.setAntiAlias(true);
paint.setTypeface(typeface);
paint.setColor(color);
paint.setTextSize(fontSizePX);
int textWidth = (int) (paint.measureText(text) + pad * 2);
int height = (int) (fontSizePX / 0.75);
Bitmap bitmap = Bitmap.createBitmap(textWidth, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
float xOriginal = pad;
canvas.drawText(text, xOriginal, fontSizePX, paint);
return bitmap;
}
public static int convertDiptoPix(Context context, float dip) {
int value = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, context.getResources().getDisplayMetrics());
return value;
}
This solution will create a bitmap that is the exact size required to fit the text.
/**
* Creates and returns a new bitmap containing the given text.
*/
public static Bitmap createTextBitmap(final String text, final Typeface typeface, final float textSizePixels, final int textColour)
{
final TextPaint textPaint = new TextPaint();
textPaint.setTypeface(typeface);
textPaint.setTextSize(textSizePixels);
textPaint.setAntiAlias(true);
textPaint.setSubpixelText(true);
textPaint.setColor(textColour);
textPaint.setTextAlign(Paint.Align.LEFT);
Bitmap myBitmap = Bitmap.createBitmap((int) textPaint.measureText(text), (int) textSizePixels, Bitmap.Config.ARGB_8888);
Canvas myCanvas = new Canvas(myBitmap);
myCanvas.drawText(text, 0, myBitmap.getHeight(), textPaint);
return myBitmap;
}
As mentioned elsewhere, the bitmap can then be assigned to a widget's ImageView.
final Bitmap textBitmap = createTextBitmap(text,
FontManager.get().getTypeface("slab-serif", 0),
context.getResources().getDimension(R.dimen.widget_font_size_large),
context.getResources().getColor(R.color.widget_text)
);
views.setImageViewBitmap(R.id.widget_cardTextImage, textBitmap);
This has the advantage of producing a bitmap that will never undershoot or overshoot the text it should contain, which is important for widgets as their dimensions vary between devices and versions.