You will hardly see any Android app that allows its users to be able to choose from a set of fonts to use for the entire app, based on user preference. The main reason is that it is difficult to implement!
Why should you bother?
Accessibility is a key aspect that every app developer should focus on. Imagine an app with amazing tools but one that can hardly be used. You do not want to lose your user base!
I used to neglect it, but that’s why I’m writing this post.
If you follow me on any social media, or here on my blog, you know I built JekyllEx to be able to manage Jekyll blogs from my Android device.
Recently, I Adam reached out Discuss their chronic headaches triggered by fonts and colors that do not fit their eyes, and it would be great if I would give some settings to be able to adjust it based on user preferences.
I quickly went to check out what the accessibility guidelines of Android have to say.
But to my surprise – I did not find anything. If you look at these guidelines, you will find that Google places great emphasis on developers taking measures and making their app accessible to all types of users. But such a common problem has not been addressed. Believe me, there are a lot of people with different levels of such reading problems.
And I usually do not allow such settings in apps, but I thought it would be a great challenge to overcome, because for the most part, all the solutions that already exist are ineffective: most of the answers to flood overflow seek to pass the ViewGroup
The children of and apply a custom font when they find text.
I had a few other thoughts and it was clear that creating an Android library would somehow solve this problem.
The challenge
In broad terms, the Android app is just a set of View
(S), held together by ViewGroup
(S), which perform certain actions when loading, pressing, etc. All this together makes the app functional.
But here’s the catch – each landscape has its own Context
, Which gives access to the current state of the display, which makes it difficult to think about how to apply the multi-font feature, since each display needs a separate treatment to update its font.
Here is a typical example of how to update a single font TextView
:
val typeface = ResourcesCompat.getFont(this@MainActivity, R.font.source_code_pro)
binding.helloWorld.typeface = typeface
Imagine you have 20+ text views, or rather RecyclerView (as in JekyllEx), Where each of the items has a significantly larger number of TextView
(That).
Here, Each item RecyclerView There are actually 8 text views! Imagine updating the font manually for each view, one by one. It will be really uncomfortable!
I looked at some questions about pile overflow and as I said before, most of them were old and inefficient.
the solution
From the beginning I knew I would keep the default font in a SharedPreference
. For those who do not know about this, this is the way for Android to allow apps to store simple data with a key-value value that the app can use without writing access to the disk. In most cases, it is enough to use SharedPreference
Instead of writing to disk and it was very useful in this case.
I would store the resource ID, an integer ID given to all types of resources in each application, b SharedPreference
, And retrieve this value to apply the font when the display is inflated (processed on the screen).
This was the most efficient way I could invent, that SharedPreference
It really is optimal. The values are cached and retrieving multiple values in a short time does not affect performance much.
There is another way, by changing the themes.xml
Values while running and applying fonts directly from the styles themselves, but this requires a minimum API level of 23 (Android 6.0). So it will not be backwards compatible and will cause the app to crash in lower Android versions. I did not want to do that.
The result
Here is the library I built:
Once you add Ponties For your project, you need to perform certain steps mentioned in the README of the repository and your project will go into intelligent use Fontize
Displays that can work unified and can change fonts quickly.
Here’s a demo of what you can achieve with Fontize:
To set the default font for the app, you just need to add this line of code just below onCreate()
Function in the activity of your application launcher (the one that is activated when you click on the application icon) only once:
Fontize(this).setDefaultFont(R.font.exo_2)
Internally, this function creates a SharedPreference
Value if it does not already exist:
fun setDefaultFont(resourceId: Int) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)
val fontId = sharedPref.getInt("fontFamily", ResourcesCompat.ID_NULL)
if (fontId == ResourcesCompat.ID_NULL) {
sharedPref.edit()
.putInt("fontFamily", resourceId)
.apply()
}
}
To update the font for the entire app, you just need to run this code and Fontize will handle it automatically for you:
Fontize(this).updateFont(R.font.zen_old_mincho)
Here’s the interesting part, this function just updates the fontFamily
Value stored in SharedPreference
For the app:
fun updateFont(resourceId: Int) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)
sharedPref.edit()
.putInt("fontFamily", resourceId)
.apply()
}
The actual work takes place in the display classes. Let’s take the example of FontizeTextView
, Or any similar class. It only expands the parent view and applies the font by selecting its value SharedPreference
:
class FontizeTextView(
context: Context,
attrs: AttributeSet
) : AppCompatTextView(context, attrs) {
init {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val fontId = prefs.getInt("fontFamily", ResourcesCompat.ID_NULL)
if (fontId != ResourcesCompat.ID_NULL) {
val typeface = ResourcesCompat.getFont(context, fontId)
this.typeface = typeface
}
}
}
All this code does is bypass the default view to apply the font family as soon as it inflates. Lessons are similar to views that support texts within them, such as ways to work around the problem MenuItem
(Q) f Toolbar
(s), will be shipped soon.
If you need to look at a live project that uses Fontize in production- Check out the JekyllEx app on GitHub. It does not use the initial version released in Jitpack, but it does use a custom fork according to its needs and requirements, but Fontize will develop soon and you can do much more than just TextViews
😄
Summary
Believe me or not, start this project, and finish the base version with work FontizeTextView
, For this post on jitpack- it all ended in just two hours! font Deserves a star for this effort 😎.
I hope you learned something new from this post. If you want to continue reading quality content for Android development, consider joining my newsletter, fill in the box at the top of the article.
Comment and let me know which topic I should choose to publish an article for next week. All kinds of comments are welcome 🙂
Thanks and happy coding!