Ранее мы писали о том, Google добавили в Android поддержку шрифтов из своего каталога Google Fonts. В этой статье мы подробно рассмотрим, как можно это реализовать в своём приложении.
Благодаря Google Fonts вы можете использовать тысячи самых разных шрифтов в своих приложениях. Более того, эта возможность теперь распространяется не только на Android O (API 26), но также на все устройства, начиная с API 14, благодаря использованию библиотеки поддержки.
Использование загружаемых шрифтов несёт в себе следующие преимущества:
- уменьшение размера APK (вам не нужно включать в проект .ttf файлы со шрифтами);
- приложение на устройстве пользователя могут совместно использовать шрифты из одного источника, не раздувая хранилище избыточными файлами.
Как это работает?
Благодаря встроенной поддержке шрифтов, особенно подчёркивается второй пункт. Например, ниже представлена схема, по которой разные приложения могут пользоваться общими шрифтами.
По этой схеме можно увидеть, что приложения, запрашивающие шрифты, обращаются к одному поставщику, указав контракт на шрифт. Поэтому если одно приложение уже запросило шрифт, другие приложения не будут запускать загрузку и сразу получат шрифт из кеша.
Такая схема необходима, чтобы система не вносила вредоносного кода в файлы.
Реализация
В приложении Фонарик используется таймер со специальным шрифтом, который хранится в папке assets проекта. Чтобы уменьшить размер APK файла, перепишем приложение, используя загружаемые шрифты.
Добавить загружаемые шрифты в своё приложение можно двумя способами.
Через Android Studio
Чтобы добавить таким способом, перейдём на разметку с виджетом, шрифт которого нужно изменить. На вкладке Design нужно кликнуть по виджету, затем в свойствах найти fontFamily и выбрать More fonts…
Откроется окно со списком всех шрифтов, доступных в Google Fonts, где можно выбрать любой понравившийся. Выберем шрифт Orbitron и нажмём ОК. Важно здесь выбрать именно Create downloable font, поскольку Add font to project просто добавит шрифт в проект, что противоречит текущей цели.
После этого Android Studio сама создаст необходимые файлы. В папке res/font будет создан файл orbitron.xml, в папке res/values файлы preloaded_fonts.xml и font_certs.xml.
orbitron.xml
<?xml version="1.0" encoding="utf-8"?> <font-family xmlns:app="http://schemas.android.com/apk/res-auto" app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderPackage="com.google.android.gms" app:fontProviderQuery="Orbitron" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"> </font-family>
Этот файл содержит определения для Android о семействе шрифтов. Как вы можете видеть, в нём перечислены fontProvider, fontProviderCerts, которые были автоматически созданы в Android Studio.
preloaded_fonts.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="preloaded_fonts" translatable="false"> <item>@font/orbitron</item> </array> </resources>
Android Studio создаёт этот файл, чтобы помочь предварительно загрузить шрифты. Это нужно, чтобы избежать задержки, когда шрифт не отображается при старте приложения. Рендеринг картинки является синхронным процессом, поэтому первый рендер может занять некоторое время, пока Android загружает шрифт. Объявление этого файла в манифесте нужно для того, чтобы приложение получило шрифт в начале работы, до отрисовки экрана.
Android Studio сама добавляет в манифест метатег, содержащий путь до файла preloaded_fonts.xml.
<meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts"/>
font_certs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="com_google_android_gms_fonts_certs"> <item>@array/com_google_android_gms_fonts_certs_dev</item> <item>@array/com_google_android_gms_fonts_certs_prod</item> </array> <string-array name="com_google_android_gms_fonts_certs_dev"> <item> <!-- Строка с сертификатом --> </item> </string-array> <string-array name="com_google_android_gms_fonts_certs_prod"> <item> <!-- Строка с сертификатом --> </item> </string-array> </resources>
Этот файл содержит огромные зашифрованные сертификаты, которые проверяют шрифты.
Теперь мы может просто указать в разметке у любого виджета свой шрифт в атрибуте fontFamily и увидеть результат.
Здесь новый шрифт используется только у одного виджета. Если вы хотите поменять шрифт всего приложения, вам нужно перейти в styles.xml и добавить его в тему вашего приложения.
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:fontFamily">@font/orbitron</item> </style>
Как использовать загружаемые шрифты на старых устройствах?
Для этого вам нужно добавить библиотеку поддержки в файл build.gradle модуля приложения.
compile "com.android.support:support-compat:27.0.1"
Кроме того, библиотека поддержка была перенесена в maven репозиторий Google, поэтому вам больше не нужен SDK Manager для загрузки библиотеки. Чтобы добавить maven репозиторий Google, добавьте следующую строку в repositories файла build.gradle модуля проекта.
repositories { google() ... репозитории }
Программное добавление загружаемых шрифтов
Чтобы добавить шрифт программно, нам понадобятся два класса:
- FontRequest для создания запроса на получение шрифта
- FontsContract для создания объекта Typeface после получения результата запроса шрифта
Приложение будет извлекать шрифты из провайдера с помощью API FontsContract. У каждого провайдера есть свой собственный набор ограничений на версии Android и язык запросов, который он поддерживает.
Итак, для начала создадим экземпляр класса FontRequest.
FontRequest fontRequest = new FontRequest("com.google.android.gms.fonts", "com.google.android.gms", "Orbitron", R.array.com_google_android_gms_fonts_certs);
В параметрах указываются:
- Владелец провайдера шрифтов
- Пакет провайдера шрифтов для проверки личности провайдера
- Строка запроса шрифта. О том, как формируется запрос, мы писали здесь.
- Список сертификатов. Необязателен, если вы запрашиваете шрифты из предустановленных провайдеров, однако необходим, если используется библиотека поддержки.
Затем нужно создать экземпляр класса FontsContractCompat.FontRequestCallback, чтобы получить результат выполнения запроса в виде объекта Typeface или же сообщение об ошибке в случае неудачи.
FontsContractCompat.FontRequestCallback fontRequestCallback = new FontsContractCompat.FontRequestCallback() { @Override public void onTypefaceRetrieved(Typeface typeface) { pb.setTypeface(typeface); } @Override public void onTypefaceRequestFailed(int reason) { Toast.makeText(MainActivity.this, "Failed download font programmatically", Toast.LENGTH_LONG).show(); } };
Теперь достаточно вызвать метод FontsContract.requestFont(), чтобы получить шрифт. Этот метод проверит, находится ли шрифт в кеше. Если его там нет, то он обращается к провайдеру шрифтов, чтобы извлечь шрифт и передать в callback.
FontsContract.requestFont(this, fontRequest, fontRequestCallback, getThreadHandler());
Как только FontRequestCallback получает объект Typeface, он устанавливает его в нужный виджет. Это наглядно можно увидеть на GIF ниже.
Заключение
Вот и всё! Теперь с помощью загружаемых шрифтов вы можете использовать огромный ассортимент самых разных шрифтов и при этом не увеличивать размер вашего APK файла.