
What does your text look like?
- Transfer
Friends, great all friday. We want to share with you a translation of an article prepared especially for students of the course “Android-developer. Advanced Course . ” Have a good reading.

How to declaratively style text on Android.

The Virginia Poltrack illustration

What and when to use?
This article describes various approaches to declarative stylization of text (that is, when you define styles in an XML file), discusses the scope and priority of each method.
You should read the entire post, but here is a summary.
Remember the priority order of various styling methods - if you are trying to stylize some text and do not see the expected results, then most likely your changes are overridden by something with a higher priority in this hierarchy:

Hierarchy of text styling methods
I would suggest the following order actions for styling:
You can directly set attributes
What happens under the hood when you style the view? If you ever wrote your custom view, you probably saw a call to context.obtainStyledAttributes (AttributeSet, int [], int, int). Thus, the view-system in Android passes to the view the attributes specified in the layout. The parameter
View → Style The
attributes defined directly in the view always “prevail” and override the attributes defined in the style. Note that a combination of style and view attributes is applied ; defining an attribute in view, which is also specified in the style, does not cancelwhole style. It should also be noted that in your view there is no real way to determine where the stylization comes from; This is decided by the view system for you once in a similar call. You cannot get both options and choose.
Although styles are extremely useful, they have their limitations. One of them is that you can only apply one style to the view (as opposed to something like CSS, where you can apply multiple classes). We
There
So what is going on here? Essentially, it
View → Style → TextAppearance
Since the text appearance is checked first, any attributes defined either directly in the view or in style will override it.
C
We reviewed the version
Styling attributes supported
Here are some attributes
Therefore,
When we looked at how the Android view system resolves attributes (
When determining the final value of a particular attribute, four input parameters come into play:
The order of styling priorities from Theme documentation
We will return to the topics, but let's take a look at the default styles first. What is this default style? To answer this question, I think it would be useful to make a small exit from the topic

Standard Button
Why? If you look at the source code
It's all! Here is the whole class (no comment). You can check it yourself here . I'll wait. So where does the background, capital letters, ripple, etc. come from? You may have missed, but it will all be defined in the constructor with 2 arguments; one that is called when layout is taken from XML. This is the last parameter that determines
Back to
The best approach might be to specify your own default style for everyone
With this in mind, our priority rule takes the form:
View → Style → Default Style → TextAppearance
As part of the resolution of the view system’s attributes, this slot is filled after the styles (so that everything in the default style is canceled by the applied style or view attributes), but still will override text appearance. Default styles can be very convenient. If you ever decide to write your own custom view, they can be a powerful way to implement default behavior, making it easy to customize.
If you inherit the widget and do not specify your own default style, then be sure to use the default parent class style in the constructors (do not pass just 0). For example, if you inherit from
As mentioned earlier, there is another (last, I promise) way of providing styling information. Another place
One example would be when you try to change the font throughout the application. You can use one of the methods described above, but manually adjusting the styles / appearance of the text everywhere will be monotonous and unsafe, and the default styles will work only at the widget level; subclasses can override this behavior, for example buttons define their own
Now any view that supports this attribute will pick it up if it is not overridden by something with a higher priority:
View → Style → Default Style → Theme → TextAppearance
Again, since this is part of the view styling system, it will override everything , which is provided in text form, but will be overridden by any more specific attributes.
Remember this priority. In our example with a font for the entire application, you can expect
This entire article was devoted to the declarative formatting of text at the view level, that is, how to style everything
→ Spantastic text styling with Spans
→ Underspanding spans
I will mention this to complete the picture, to keep in mind that program styling and spans will be at the top of the order of priority:
Span → Setters → View → Style → Default Style → Theme → TextAppearance
Although there are several ways to style text, understanding the differences between methods and their limitations helps you find the right tool for a specific task or understand why one method takes precedence over another.
Have a nice text styling!
We invite everyone to a free webinar in the framework of which we will get acquainted with the DI framework Dagger 2: we will learn how Dagger2 generates code, we will deal with JSR 330 annotations and Dagger2 constructs, we will learn how to use Dagger2 in a multi-module application and consider the Dagger Android Injector.

How to declaratively style text on Android.

The Virginia Poltrack illustration
TextView
in Android apps provides several attributes for styling text and various ways to apply them. These attributes can be set directly in the layout, apply a style to the view or theme to the layout, or, if you want, set textAppearance. But what of this should be used? And what happens if you combine them? 
What and when to use?
This article describes various approaches to declarative stylization of text (that is, when you define styles in an XML file), discusses the scope and priority of each method.
tl; dr;
You should read the entire post, but here is a summary.
Remember the priority order of various styling methods - if you are trying to stylize some text and do not see the expected results, then most likely your changes are overridden by something with a higher priority in this hierarchy:

Hierarchy of text styling methods
I would suggest the following order actions for styling:
- Set any application style to
textViewStyle
as the default style for your theme. - Install the (small) set
TextAppearance
that your application will use (or use / inherit from MaterialComponent styles ), and reference them directly from your view - Create
style
by setting attributes that are not supportedTextAppearance
(which themselves will determine one of yoursTextAppearance
). - Perform any unique styling directly in the layout.
Show some style
You can directly set attributes
TextView
in a layout, but this approach can be more tedious and unsafe. Imagine that in this way you are trying to update the color of all TextViews in the application. As with all other views, you can (and should!) Use styles instead to ensure consistency, reuse, and ease of updating. For this purpose, I recommend creating styles for text whenever you probably want to apply the same style to multiple views. This is extremely simple and largely supported by the Android view system. What happens under the hood when you style the view? If you ever wrote your custom view, you probably saw a call to context.obtainStyledAttributes (AttributeSet, int [], int, int). Thus, the view-system in Android passes to the view the attributes specified in the layout. The parameter
AttributeSet
, in fact, can be considered as a map of the XML parameters that you specify in your layout. If the AttributeSet sets the style, the style is read first , and then the attributes specified directly in the view are applied to it. Thus, we come to the first rule of priority. View → Style The
attributes defined directly in the view always “prevail” and override the attributes defined in the style. Note that a combination of style and view attributes is applied ; defining an attribute in view, which is also specified in the style, does not cancelwhole style. It should also be noted that in your view there is no real way to determine where the stylization comes from; This is decided by the view system for you once in a similar call. You cannot get both options and choose.
Although styles are extremely useful, they have their limitations. One of them is that you can only apply one style to the view (as opposed to something like CSS, where you can apply multiple classes). We
TextView
, however, there is a trick, it provides an attribute TextAppearance
, which works similarly style
. If you style text through TextAppearance
, then leave the attribute style
free for other styles, which looks practical. Let's take a closer look at what it is TextAppearance
and how it works.Textappearance
There
TextAppearance
is nothing magical (for example, a secret mode for applying several styles that you should not know about !!!!), TextView
saving you some unnecessary work. Let's look at the constructor TextView
to understand what is happening.TypedArray a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes);
TypedArray appearance = null;
int ap = a.getResourceId(com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
a.recycle();
if (ap != -1) {
appearance = theme.obtainStyledAttributes(ap, com.android.internal.R.styleable.TextAppearance);
}
if (appearance != null) {
readTextAppearance(context, appearance, attributes, false);
appearance.recycle();
}
// a little later
a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
readTextAppearance(context, a, attributes, true);
So what is going on here? Essentially, it
TextView
first looks to see if you indicated android:textAppearance
, if so, it loads that style and applies all the properties that are listed there. Later, he loads all the attributes from the view (which he remembers, including the style) and applies them. So we come to the second priority rule: View → Style → TextAppearance
Since the text appearance is checked first, any attributes defined either directly in the view or in style will override it.
C
TextAppearance
should be aware of another caveat: it supports a subset of the style attributes that it offers TextView
. To better understand what I mean, let's go back to this line: obtainStyledAttributes(ap, android.R.styleable.TextAppearance);
We reviewed the version
receiveStyledAttributes
with 4 arguments, this 2-argument version is slightly different. She looks at the given style (as defined by the first parameter id
) and filters it only according to the attributes in the style that appear in the second parameter, the array attrs
. Thus, styleable android.R.styleable.TextAppearance
defines the scope TextAppearance
. Looking at this definition, we see that it TextAppearance
supports many, but not all, attributes that it supportsTextView
.
Styling attributes supported
TextAppearance
Here are some attributes
TextView
that are not included inTextAppearance
:lineHeight[Multiplier|Extra]
,lines
,breakStrategy
andhyphenationFrequency
. TextAppearance
works at the level of characters, not paragraphs, so attributes that affect the entire layout are not supported. Therefore,
TextAppearance
it is very useful, it allows us to define a style oriented to the text stylization attributes, and leaves itstyle
free in view for other purposes. However, it has a limited scope and is at the bottom of the priority chain, so don't forget about the limitations.Reasonable defaults
When we looked at how the Android view system resolves attributes (
context.obtainStyledAttributes
), we actually simplified it a bit. It calls theme.obtainStyledAttributes (using the current Theme Context
'a). When checking the link , the priority order that we examined earlier is shown, and 2 more places are indicated that he is looking for to resolve attributes: the default style for view and the theme. When determining the final value of a particular attribute, four input parameters come into play:
- Any attribute values in this AttributeSet.
- The style resource specified in the AttributeSet (named "style").
- The default style specified by defStyleAttr and defstyleres
- Basic values in this thread.
The order of styling priorities from Theme documentation
We will return to the topics, but let's take a look at the default styles first. What is this default style? To answer this question, I think it would be useful to make a small exit from the topic
TextView
and look at a simple one Button
. When you paste <
Button
>
into your layout, it looks something like this. 
Standard Button
Why? If you look at the source code
Button
, you will see that it is rather meager:public class Button extends TextView {
public Button(Context context) {
this(context, null);
}
public Button(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.buttonStyle);
}
public Button(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override public CharSequence getAccessibilityClassName() {
return Button.class.getName();
}
@Override public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
if (getPointerIcon() == null && isClickable() && isEnabled()) {
return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND);
}
return super.onResolvePointerIcon(event, pointerIndex);
}
}
It's all! Here is the whole class (no comment). You can check it yourself here . I'll wait. So where does the background, capital letters, ripple, etc. come from? You may have missed, but it will all be defined in the constructor with 2 arguments; one that is called when layout is taken from XML. This is the last parameter that determines
defaultStyleAttr
incom.android.internal.R.attr.buttonStyle
. This is the default style, which is essentially an indirect reference point, allowing you to specify the default style. It does not point directly to the style, but allows you to point to one of those specified in your topic that it will check when resolving attributes. And that’s exactly what all the themes you usually inherit from do to provide the look and feel of standard widgets. For example, if you look at the topic Material, it defines @style/Widget.Material.Light.Button
, and it is this style that provides all the attributes that it will pass theme.obtainStyledAttributes
if you did not specify anything else. Back to
TextView
, it also offers a default style:textViewStyle
. This can be very convenient if you want to apply some styles to every TextView in your application. Suppose you want to set the default line spacing to 1.2. You can do this with help style/TextAppearance
and try to apply it during the code review (or maybe even with the help of an elegant custom rule in Lint), but you need to be vigilant and be sure that you will recruit new team members, be careful with refactoring, etc. The best approach might be to specify your own default style for everyone
TextView
in the application that sets the desired behavior. You can do this by setting your own style for textViewStyle
, which is inherited from the platform or from MaterialComponents/AppCompat
the default.
With this in mind, our priority rule takes the form:
View → Style → Default Style → TextAppearance
As part of the resolution of the view system’s attributes, this slot is filled after the styles (so that everything in the default style is canceled by the applied style or view attributes), but still will override text appearance. Default styles can be very convenient. If you ever decide to write your own custom view, they can be a powerful way to implement default behavior, making it easy to customize.
If you inherit the widget and do not specify your own default style, then be sure to use the default parent class style in the constructors (do not pass just 0). For example, if you inherit from
AppCompatTextView
and write your own constructor with 2 arguments, be sure to pass android.R.attr.textViewStyle как defaultStyleAttr
( as here ), otherwise you will lose the behavior of the parent class.Topics
As mentioned earlier, there is another (last, I promise) way of providing styling information. Another place
theme.obtainStyledAttributes
will look right into the topic itself. That is, if you add a style attribute to your theme, for example android:textColor
, the view system will select it as a last resort. As a rule, it is a bad idea to mix theme attributes and style attributes, that is, what you apply directly to the view, as a rule, should never be set for the theme (and vice versa), but there are a couple of rare exceptions.One example would be when you try to change the font throughout the application. You can use one of the methods described above, but manually adjusting the styles / appearance of the text everywhere will be monotonous and unsafe, and the default styles will work only at the widget level; subclasses can override this behavior, for example buttons define their own
android:buttonStyle
, which yours won't pick up android:textViewStyle
. Instead, you can specify the font in your theme:
Now any view that supports this attribute will pick it up if it is not overridden by something with a higher priority:
View → Style → Default Style → Theme → TextAppearance
Again, since this is part of the view styling system, it will override everything , which is provided in text form, but will be overridden by any more specific attributes.
Remember this priority. In our example with a font for the entire application, you can expect
Toolbar
this font to pick up, as it contains the title, which is TextView
. The Toolbar class itself, however, defines a default style, containing titleTextAppearance
one that defines android:fontFamily
, and sets it directly in the headerTextView
by overriding the theme level value. Topic-level styles can be useful, but easy to override, so make sure they are applied properly.Bonus: Unresolved Issues
This entire article was devoted to the declarative formatting of text at the view level, that is, how to style everything
TextView
during filling. Any style applied after filling (for example textView.setTextColor(…)
) will override declarative styling. TextView
also supports smaller styles through Span
. I will not go into this topic, as it is described in detail in articles by Florina Muntenescu . → Spantastic text styling with Spans
→ Underspanding spans
I will mention this to complete the picture, to keep in mind that program styling and spans will be at the top of the order of priority:
Span → Setters → View → Style → Default Style → Theme → TextAppearance
Choose your style
Although there are several ways to style text, understanding the differences between methods and their limitations helps you find the right tool for a specific task or understand why one method takes precedence over another.
Have a nice text styling!
We invite everyone to a free webinar in the framework of which we will get acquainted with the DI framework Dagger 2: we will learn how Dagger2 generates code, we will deal with JSR 330 annotations and Dagger2 constructs, we will learn how to use Dagger2 in a multi-module application and consider the Dagger Android Injector.