Как использовать пользовательский шрифт в виджетах?

У меня есть виджет цифровых часов. Как я могу использовать пользовательский шрифт из активов / шрифтов в качестве шрифта по умолчанию в текстовом представлении, показывающем часы?

Это мой код:

package android.tristan.widget.digiclock; import java.util.Calendar; import android.app.PendingIntent; import android.app.Service; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.os.Vibrator; import android.text.format.DateFormat; import android.widget.RemoteViews; public class DigiClock extends AppWidgetProvider { @Override public void onDisabled(Context context) { super.onDisabled(context); context.stopService(new Intent(context, UpdateService.class)); } public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); if(intent.getAction().equals("android.tristan.widget.digiclock.CLICK")) { Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(50); final Intent alarmClockIntent = new Intent(Intent.ACTION_MAIN, null); alarmClockIntent.addCategory(Intent.CATEGORY_LAUNCHER); final ComponentName cn = new ComponentName("com.android.deskclock", "com.android.deskclock.AlarmClock"); alarmClockIntent.setComponent(cn); alarmClockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(alarmClockIntent); } if(intent.getAction().equals("android.tristan.widget.digiclock.CLICK_2")) { Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(50); final Intent calendarIntent = new Intent(Intent.ACTION_MAIN, null); calendarIntent.addCategory(Intent.CATEGORY_LAUNCHER); final ComponentName cn = new ComponentName("com.android.calendar", "com.android.calendar.LaunchActivity"); calendarIntent.setComponent(cn); calendarIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(calendarIntent); } } @Override public void onEnabled(Context context) { super.onEnabled(context); context.startService(new Intent(UpdateService.ACTION_UPDATE)); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); context.startService(new Intent(UpdateService.ACTION_UPDATE)); final int Top = appWidgetIds.length; final int Bottom = appWidgetIds.length; for (int i=0; i<Top; i++) { int[] appWidgetId = appWidgetIds; RemoteViews top=new RemoteViews(context.getPackageName(), R.layout.main); Intent clickintent=new Intent("android.tristan.widget.digiclock.CLICK"); PendingIntent pendingIntentClick=PendingIntent.getBroadcast(context, 0, clickintent, 0); top.setOnClickPendingIntent(R.id.TopRow, pendingIntentClick); appWidgetManager.updateAppWidget(appWidgetId, top); } for (int i=0; i<Bottom; i++) { int[] appWidgetId = appWidgetIds; RemoteViews bottom=new RemoteViews(context.getPackageName(), R.layout.main); Intent clickintent=new Intent("android.tristan.widget.digiclock.CLICK_2"); PendingIntent pendingIntentClick=PendingIntent.getBroadcast(context, 0, clickintent, 0); bottom.setOnClickPendingIntent(R.id.BottomRow, pendingIntentClick); appWidgetManager.updateAppWidget(appWidgetId, bottom); } } public static final class UpdateService extends Service { static final String ACTION_UPDATE = "android.tristan.widget.digiclock.action.UPDATE"; private final static IntentFilter sIntentFilter; private final static String FORMAT_12_HOURS = "h:mm"; private final static String FORMAT_24_HOURS = "kk:mm"; private String mTimeFormat; private String mDateFormat; private String mDayFormat; private Calendar mCalendar; static { sIntentFilter = new IntentFilter(); sIntentFilter.addAction(Intent.ACTION_TIME_TICK); sIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED); sIntentFilter.addAction(Intent.ACTION_TIME_CHANGED); } @Override public void onCreate() { super.onCreate(); reinit(); registerReceiver(mTimeChangedReceiver, sIntentFilter); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(mTimeChangedReceiver); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); if (ACTION_UPDATE.equals(intent.getAction())) { update(); } } @Override public IBinder onBind(Intent intent) { return null; } private void update() { mCalendar.setTimeInMillis(System.currentTimeMillis()); final CharSequence time = DateFormat.format(mTimeFormat, mCalendar); final CharSequence date = DateFormat.format(mDateFormat, mCalendar); final CharSequence day = DateFormat.format(mDayFormat, mCalendar); RemoteViews views = new RemoteViews(getPackageName(), R.layout.main); views.setTextViewText(R.id.Time, time); views.setTextViewText(R.id.Day, day); views.setTextViewText(R.id.Date, date); ComponentName widget = new ComponentName(this, DigiClock.class); AppWidgetManager manager = AppWidgetManager.getInstance(this); manager.updateAppWidget(widget, views); } private void reinit() { mDayFormat = getString(R.string.day_format); mDateFormat = getString(R.string.date_format); mTimeFormat = is24HourMode(this) ? FORMAT_24_HOURS : FORMAT_12_HOURS; mCalendar = Calendar.getInstance(); } private static boolean is24HourMode(final Context context) { return android.text.format.DateFormat.is24HourFormat(context); } private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { reinit(); } update(); } }; } } 

Необходимо сделать шрифт на холсте, а затем передать его в растровое изображение и назначить его в ImageView. Вот так:

 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; } 

Это часть, выполняющая шрифт для изображения thingie, и вот как его использовать:

 String time = (String) DateFormat.format(mTimeFormat, mCalendar); RemoteViews views = new RemoteViews(getPackageName(), R.layout.main); views.setImageViewBitmap(R.id.TimeView, buildUpdate(time)); 

Как вы могли заметить, этот код просто показывает текущее время в представлении изображения, но его можно легко настроить в соответствии с любыми потребностями.

Редактировать:

ARGB_4444 устарел для ARGB_8888, как указано в документации

Это поле было устарело в API-интерфейсе 13. Из-за низкого качества этой конфигурации рекомендуется использовать ARGB_8888.

Я немного изменил размер меры, поэтому растровое изображение будет поддерживать разные шрифты. Он просто поддерживает однострочный текст.

 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_4444); 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; } 

Это отображает шрифт в растровое изображение, а затем назначает растровое изображение 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; } 

Это решение создаст растровое изображение, которое является точным размером, необходимым для текста.

 /** * 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; } 

Как упоминалось в другом месте, растровое изображение затем может быть присвоено 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); 

Это имеет преимущество в том, что вы создаете растровое изображение, которое никогда не будет отставать или превышать текст, который он должен содержать, что важно для виджетов, поскольку их размеры различаются между устройствами и версиями.

Я не могу найти его сейчас, но я задал тот же вопрос и получил от Google ответ, что это невозможно. Вы действительно ограничены в том, что вы можете делать с AppWidgets, например, вы можете использовать только определенные виджеты пользовательского интерфейса, и вы не можете использовать пользовательские шрифты.

 remoteviews.setTextViewText(textview_id, new SpannableStringBuilder(Html.fromHtml("<b>"+some_text_vaeiable"+"</b>")) ); 

Вот как я это делаю в своих приложениях, также должен применяться к виджетам.

 Typeface customfont = Typeface.createFromAsset(getAssets(), "fonts/somefont.ttf"); TextView textview = (TextView) findViewById(R.id.textview); textview.setTypeface(customfont); textview.setText("Hey custom font!"); 
Intereting Posts