Texting with style

May 15th 2020

By Elza Kalač, Android Developer at Klika

 

When I first got introduced to Android Development, I was amazed by resources and layout files. It was new to me, and I never had the opportunity to work with that kind of files.  

Being able to customize everything just by adding a simple statement in element definition astonished me. Wht got me interested in particular was text styling, since it is a really important part of every app. If it is right, no one will notice it, but if it is wrong for just a pixel, it will be such a tragedy.  

Shortly after I first discovered all these possibilities, I have been adding font, size, text color, etc. to every text element to make them match the design. After a while, I tried to optimize that process, by defining styles that I would use for similar text views. At first, I defined styles by the feature they were used to. Like:  

 

<style name="MyCoolFeatureDescripionTextStyle"> 

  <item name="android:fontFamily">@font/roboto_300</item> 

  <item name="android:textSize">26sp</item> 

  <item name="android:textColor">#FF23A5</item> 

</style> 

 

Not so long after, styles.xml  was overwhelmed by styles that cannot be reused, since they are personalized for a single feature, and mixed with styles for other UI elements in the app. There was no motivation to use them since for every new feature you had to define a new style and use it on a few elements. Changing and organizing styles were necessary, but there was no clear idea of how to do it, simply and consistently.  

The main motivation and source of ideas was the Typography board, which was provided by the design team.  

The first step was to separate styles related to text view into the new .xml file. That way, they are centralized and can easily be organized.  

After that, I created text styles that match provided fonts in typography, naming them as they were named in typography, so they can be reused in different places in the app.  

In general, it looks like this:  

 

<style name="Heading3"> 

  <item name="android:fontFamily">@font/roboto_300</item> 

  <item name="android:textSize">@dimen/text_34</item> 

</style> 

 

<style name="Heading4"> 

  <item name="android:fontFamily">@font/roboto_500</item> 

  <item name="android:textSize">@dimen/text_26</item> 

</style> 

 

<style name="Body1"> 

  <item name="android:fontFamily">@font/roboto_300</item> 

  <item name="android:textSize">@dimen/text_16</item> 

</style> 

 

To effectively define text styles, I extracted text sizes to dimen.xml, since in that way they can be easily overridden for some other configurations(screen size, orientation, etc). Also, it is easier to export them if that is needed. Exporting text sizes and styles provide more consistency across the app since the developer uses values from a limited and predefined set.  

Fonts are included in the app and named based on their weight. Font weight can also be set through a parameter, so there is no need to import multiple font files. This decision is on the development and design team to figure out what fits the best to project and product. You can find more info about that here.  

As seen in the code above, only structural properties are listed, like font family and text size, but you can add spacing, some paragraph properties, line height, includeFontPadding, etc.  

Using the component library, I defined text color that were used in the app, so I created text styles combining text styles listed above:  

 

<style name="Body2.Black"> 

  <item name="android:textColor">@color/black</item> 

</style> 

 

<style name="Heading8.White"> 

  <item name="android:textColor">@color/white</item> 

</style> 

 

As seen above, styles can be inherited, so you can create more customized text style, yet still uniformed with others and their usage in the app.  

 

<style name="Heading10.White.NoAllCaps"> 

  <item name="android:textAllCaps">false</item> 

</style> 

 

If you use the dot notation to extend a style, and you also include the parent attribute, then the parent styles override any styles inherited through the dot notation. 

Defined like this, they can be used in TextView as style or android:textAppereance. The main difference between these two is that text appearance represents a set of attributes related only to a character. What I experienced as an issue it when I attempted to define "android:lineSpacingMultiplier", is that it only applies to textView if text style is set thought style, not textAppereance.  

Styling attributes supported by TextAppearance are:  

 

<attr name="textColor" /> 

<attr name="textSize" /> 

<attr name="textStyle" /> 

<attr name="typeface" /> 

<attr name="fontFamily" /> 

<attr name="textColorHighlight" /> 

<attr name="textColorHint" /> 

<attr name="textColorLink" /> 

<attr name="textAllCaps" format="boolean" /> 

<attr name="shadowColor" format="color" /> 

<attr name="shadowDx" format="float" /> 

<attr name="shadowDy" format="float" /> 

<attr name="shadowRadius" format="float" /> 

<attr name="elegantTextHeight" format="boolean" /> 

<attr name="letterSpacing" format="float" /> 

<attr name="fontFeatureSettings" format="string" /> 

 

Some common TextView attributes not included are lineHeight[Multiplier|Extra], lines, break strategy & hyphenationFrequency. TextAppearance works at the character level, not paragraph so attributes affecting the whole layout are not supported. 

So TextAppearance is very useful, it lets us define a style focused on text styling attributes and leaves a view's style free for other uses. It does, however, have a limited scope and is at the bottom of the precedence chain, so be aware of its limitations.  

Also, there will always be exceptions. Not every text element from design will fit within pre-defined styles and you'll almost always have to improvise at some point, either by declaring some attributes directly on the view or creating some component-based style. Such situations are exceptions and should be treated like that - exceptions. And if you find yourself doing this too often you should revise your approach and process of design to development. Exporting values can be a tiresome process, especially if there is no noticeable value from doing it. 

Even if we accept the fact that it is good practice, it is still a boring process that developers lack motivation for.  

Once we introduced those changes in our app, implementing new features on UI became quite faster and efficient, with fewer UI issues. It is important to emphasize that creating predefined styles without typography or some input from the design team can we exhausting and sometimes hopeless effort. Having predefined components and their properties can facilitate and speed up the design and development process. 

Popular posts