Typeface — е клас на Android SDK от пакета android.graphics, който представлява изгледа на шрифта и се използва за персонализиране на текст в TextView и други UI компоненти. Typeface определя семейството на шрифта, неговото тегло (normal, bold) и стил (normal, italic). Според Google Developers, Typeface поддържа зареждане от TTF, OTF файлове, XML шрифтове и системни ресурси. Това е централният клас за управление на типографията в Android приложения.
Основни неща
Typeface — е Android клас, който капсулира информация за шрифта: неговото семейство (Roboto, Arial, Serif) и стилови модификатори (удебеляване, курсив). За разлика от UIFont в iOS, Typeface не съдържа информация за размер — размерът на текста се задава отделно чрез свойството textSize в TextView или TextStyle в Spannable. Typeface отговаря само за изгледа и гарнитурата на шрифта.
Класът е достъпен на всички API нива. До Android 4.4 Typeface поддържаше само ограничен набор от системни шрифтове: DEFAULT, DEFAULT_BOLD, MONOSPACE, SERIF, SANS_SERIF. От Android 8.0 (API 26) нататък се появи поддръжка за зареждане на персонализирани шрифтове чрез XML ресурси, а Android 10 добави поддръжка за вариативни шрифтове.
Android предоставя няколко вградени Typeface инстанции: Typeface.DEFAULT — системен шрифт Roboto (Material) или Noto (AOSP), DEFAULT_BOLD — удебелена версия, MONOSPACE — моноширинен шрифт за код, SERIF — шрифт със серифи (Noto Serif), SANS_SERIF — безсерифен шрифт (Noto Sans). Тези константи са достъпни без контекст и не изискват разрешения за четене на файлове.
Android системата използва Typeface за изобразяване на целия текст, включително системен UI, заглавия, етикети и известия. Всяко приложение може да презапише шрифта по подразбиране чрез тема (android:fontFamily) или програмно чрез setTypeface(). Typeface се прилага към всички компоненти, наследени от TextView: бутони, EditText и персонализирани изгледи.
Android 8.0+ позволява добавяне на шрифтове към res/font и използването им чрез XML ресурси. Файлът на шрифта (TTF или OTF) се поставя в res/font, след което се създава референция R.font.font_name. Typeface се зарежда чрез ResourcesCompat.getFont(context, R.font.font_name). Този начин е за предпочитане, тъй като шрифтът се компилира в APK и поддържа системите за оформление ProGuard.
Ресурсният начин поддържа също семейства шрифтове (font family) чрез XML файл в res/font: могат да бъдат посочени няколко файла за различни изгледи (regular, bold, italic) и системата автоматично ще избере подходящия файл при извикване на setTypeface. Това опростява типографията — достатъчно е да зададете fontFamily в темата, а Android сам ще избере подходящия файл.
Методът Typeface.create(Typeface family, int style) създава инстанция на шрифт с указано семейство и стил. Ако семейството вече има искания стил, се връща съществуващата инстанция. Ако стилът не съществува, Android го синтезира — прилага фалшиво удебеляване или изкуствен курсив към основния шрифт.
val boldTypeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)
val italicTypeface = Typeface.create(Typeface.MONOSPACE, Typeface.ITALIC)
val customTypeface = ResourcesCompat.getFont(context, R.font.montserrat_regular)
textView.typeface = boldTypeface
Синтезираното псевдо-удебеляване може да изглежда с ниско качество на тънки шрифтове. За по-добър резултат използвайте файл на шрифт с истински bold изглед. Typeface.create() с несъществуващ стил не хвърля изключение, а връща най-близката налична вариация.
За зареждане на Typeface от assets се използва Typeface.createFromAsset(assetManager, path). Шрифтът се поставя в директория src/main/assets/fonts/, а пътят се задава относително към assets. Този метод работи на всички версии на Android, но не поддържа семейства шрифтове и изисква посочване на конкретен файл за всеки изглед.
Методът Typeface.createFromFile(File) зарежда шрифт от произволен файл във файловата система. Това е полезно за шрифтове, изтеглени от мрежата или копирани във вътрешното хранилище на приложението. createFromFile също не изисква контекст, което е удобно за фонови задачи, но файлът трябва да бъде достъпен за четене.
Многократното зареждане на Typeface от assets чрез createFromAsset може да доведе до създаване на дублирани обекти. Всяко извикване на createFromAsset зарежда файла отново. Препоръчва се имплементиране на кеш за Typeface чрез HashMap, където ключът е пътят до файла, а стойността е заредената инстанция. Това е особено важно за списъци с различни типове шрифтове.
object TypefaceCache {
private val cache = mutableMapOf<String, Typeface>()
fun getTypeface(context: Context, filename: String): Typeface {
return cache.getOrPut(filename) {
Typeface.createFromAsset(context.assets, "fonts/$filename")
}
}
}
// Употреба
val typeface = TypefaceCache.getTypeface(context, "Roboto-Bold.ttf")
Кешът в паметта гарантира, че един шрифт се зарежда само веднъж на сесия на приложението. При промяна на конфигурацията (завъртане на екрана) кешът се запазва, тъй като се намира в companion обекта. За почистване на кеша при недостиг на памет използвайте WeakHashMap или слушайте onTrimMemory.
Typeface се прилага към TextView чрез метода setTypeface(Typeface tf) или setTypeface(Typeface tf, int style). Вторият вариант позволява промяна на стила (bold/italic) спрямо текущия шрифт. В XML се използва атрибутът android:fontFamily с референция към шрифта или системното семейство. За програмно задаване извикването setTypeface(monospaceTypeface) ще замени шрифта с указания.
Typeface влияе върху целия текст на TextView. Ако е необходим различен шрифт в един ред, се използва SpannableString с TypefaceSpan. TypefaceSpan приема Typeface или family и се прилага към диапазон от символи. Това е единственият начин за смесване на шрифтове в един TextView без вложени компоненти.
Приложете TypefaceSpan само към част от низа. Например стойността на променлива в текста трябва да се показва с моноширинен шрифт, а останалият текст — със системен шрифт. Създава се SpannableString и на желания диапазон се задава TypefaceSpan с MONOSPACE Typeface. Останалата част от текста остава с оригиналния шрифт на TextView.
val text = "Code: variableName"
val spannable = SpannableString(text)
spannable.setSpan(
TypefaceSpan(Typeface.MONOSPACE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannable.setSpan(
ForegroundColorSpan(Color.BLUE),
5, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
Текстът „variableName“ ще се покаже с моноширинен шрифт в син цвят, а думата „Kod:“ ще остане със системен шрифт. TypefaceSpan може да се комбинира с всякакви други span-ове за прецизен контрол над всяка част от текста.
Android поддържа няколко формата на шрифтове: TrueType (TTF), OpenType (OTF) и Web Open Font Format (WOFF2) от Android 10. TTF и OTF са основните формати за персонализирани шрифтове. XML шрифтовете (Font Family) не са отделен формат, а служат като описание кой файл да се използва за всеки изглед.
За използване на персонализиран шрифт чрез res/font създайте XML файл на семейството, където се посочват пътищата до файловете на шрифта за regular, bold и italic. След това в темата на приложението задайте android:fontFamily="@font/custom_family". Всички TextView, използващи тази тема, автоматично ще получат правилния изглед за всеки стил.
Ако шрифтът се изтегля от мрежата, запазете го в filesDir или cacheDir и го заредете чрез Typeface.createFromFile. След зареждане актуализирайте Typeface в TextView. За асинхронно зареждане използвайте coroutine или DownloadManager, а след завършване — изпратете към UI нишката чрез Handler. Това е типичен сценарий за приложения с персонализирана типография, зареждана при поискване.
// Запазване на файл с шрифт във вътрешно хранилище
val fontFile = File(context.cacheDir, "downloaded-font.otf")
fontFile.outputStream().use { output ->
// входен поток от мрежа
inputStream.copyTo(output)
}
// Създаване на Typeface от файл
val downloadedTypeface = Typeface.createFromFile(fontFile)
textView.typeface = downloadedTypeface
Преди зареждане проверете достъпността на файла: ако файлът е повреден или невалиден, Typeface.createFromFile ще хвърли RuntimeException. Препоръчва се обвиване на извикването в try-catch и в случай на грешка запазване на шрифта по подразбиране на системата.
В Jetpack Compose Typeface Android SDK не се използва директно. Вместо това Compose предоставя FontFamily и FontWeight за типография. FontFamily се зарежда чрез Font.Resource и Font.File. Системата за типография на Compose се задава чрез MaterialTheme.typography, където на всеки стил (h1, body1, button) може да бъде присвоено персонализирано FontFamily.
За зареждане на шрифт от resources Compose използва Font(R.font.font_name, weight, style). Шрифт от assets се зарежда чрез Font(assetPath = "fonts/custom.otf", weight, style). След дефиниране на шрифта, той се предава на Typography и след това се прилага чрез MaterialTheme.typography.bodyLarge и подобни стилове.
Ако съществува готов Typeface, създаден чрез Android SDK, може да се използва в Compose чрез TypefaceAdapter или чрез създаване на FontFamily на базата на Typeface. За целта вземете Typeface от Typeface.create и го предайте на FontFamily.Custom(listOf(Font(typeface))). Въпреки това се препоръчва използването на родния подход с Font.Resource, тъй като е по-добре оптимизиран за Compose.
Зареждането на шрифтове от файлове е потенциално скъпа операция. Всяко извикване на Typeface.createFromAsset или Typeface.createFromFile чете файла от диска, парсва го и създава Typeface обект. За шрифтове с размер 1-2 MB това отнема 10-50 ms при студен старт. Кеширането на Typeface е задължителна практика за приложения с персонализирани шрифтове.
Android SDK не кешира шрифтове, създадени чрез createFromAsset или createFromFile. За разлика от системните шрифтове, които са предварително заредени в процеса Zygote, персонализираните шрифтове се зареждат при всяко достъпване. Препоръчва се използване на LruCache или ConcurrentHashMap с ключ от идентификатора на шрифта. Размер на кеша — 10-20 инстанции, което покрива типичния набор от шрифтове на приложението.
Android 8.0+ оптимизира зареждането на шрифтове чрез XML Font Family. При задаване на android:fontFamily="@font/my_family" в XML оформлението, Android зарежда шрифта мързеливо — само когато компонентът стане видим. Системата също кешира шрифтове, заредени чрез ResourcesCompat.getFont(), в глобалния кеш на процеса. Това прави ресурсния начин най-производителен.
При използване на Typeface в адаптери на RecyclerView е важно да не зареждате шрифта в метода onBindViewHolder. Извикайте зареждането веднъж при създаване на адаптера или използвайте ViewHolder с предварително зареден Typeface. Ако всеки елемент от списъка изисква уникален шрифт, имплементирайте кеш чрез WeakHashMap и го почиствайте при скроллиране извън видимите позиции за икономия на памет.
Често задавани въпроси
Typeface — е конкретна инстанция на шрифт за програмно използване. FontFamily — XML ресурс, описващ група от файлове на шрифта за различни изгледи (regular, bold, italic). По време на изпълнение FontFamily се преобразува в Typeface чрез ResourcesCompat.getFont. Typeface може да бъде създаден директно от файл, заобикаляйки FontFamily.
Използвайте Typeface.createFromFile(File) или Typeface.DEFAULT. Тези методи не изискват контекст, тъй като работят с файловата система или вградени константи. За зареждане от assets или ресурси контекстът е задължителен, тъй като е необходим достъп до AssetManager и ресурсите на приложението.
Не, WebView използва CSS свойството font-family за задаване на шрифтове. За да използвате персонализиран шрифт в WebView, поставете файла на шрифта в assets и го задайте чрез @font-face в CSS. Typeface Android SDK работи само с родни UI компоненти (TextView и неговите наследници).
Да, от Android 10 (API 29). Вариативните шрифтове се зареждат чрез ResourcesCompat.getFont или Typeface.createFromFile. За настройка на осите на вариативност (weight, width) се използва FontStyle в Compose или XML атрибути. Програмната промяна на ос е възможна само чрез нисконивовото API Skia.
Най-честите причини: файлът на шрифта липсва в проекта, посочено е грешно име на файл, шрифтът е повреден или се използва синтезиран стил, който не съществува във файла. Проверете дали файлът е добавен към res/font или assets и дали името му е посочено без разширение в случая на ресурсния метод.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също