Android Styling: Themes vs Styles
The Android styling system offers a powerful way to specify
your app’s visual design, but it can be easy to misuse. Proper use of it can
make themes and styles easier to maintain, make branding updates less scary and
make it straightforward to support dark modes. This is the first in a series of
articles where Chris Banes and I will set out to demystify Android styling so
that you can make stylish apps without pulling your hair out.
In this first article, I’ll take a look at the building
blocks of the styling system: themes and styles.
Theme != Style
Both themes and styles use the same <style> syntax but
serve very different purposes. You can think of both as key-value stores where
the keys are attributes and the values are resources. Let’s take a look at
each.
What’s in a style?
A style is a collection of view attribute values. You can
think of a style as a Map<view attribute, resource>. That is the keys are
all view attributes i.e. attributes that a widget declares and you might set in
a layout file. Styles are specific to a single type of widget because different
widgets support different sets of attributes:
Styles are a collection of view attributes; specific to a
single type of widget
As you can see, each of the keys in the style are things you
could set in a layout:
Extracting them to a style makes it easy to reuse across
multiple views and maintain.
Usage
Styles are used by individual views from a layout:
Views can only apply a single style — contrast this to other
styling systems such as css on the web where components can set multiple css
classes.
Scope
A style applied to a view only applies to that view, not to
any of its children. For example, if you have a ViewGroup with three buttons,
setting the InlineAction style on the ViewGroup will not apply that style to
the buttons. The values provided by the style are combined with those set
directly in the layout (resolved using the styling precedence order).
What’s a theme?
A theme is a collection of named resources which can be
referenced later by styles, layouts etc. They provide semantic names to Android
resources so you can refer to them later e.g. colorPrimary is a semantic name
for a given color:
These named resources are known as theme attributes, so a
theme is Map<theme attribute, resource>. Theme attributes are different
from view attributes because they’re not properties specific to an individual
view type but semantically named pointers to values which are applicable more
broadly in an app. A theme provides concrete values for these named resources.
In the example above the colorPrimary attribute specifies that the primary
color for this theme is teal. By abstracting the resource with a theme, we can
provide different concrete values (such as colorPrimary=orange) in different
themes.
Themes are a collection of named resources, useful broadly
across an app
A theme is similar to an interface. Programming to an
interface allows you to decouple the public contract from the implementation
allowing you to provide different implementations. Themes play a similar role;
by writing our layouts and styles against theme attributes, we can use them
under different themes, providing different concrete resources.
Roughly equivalent pseudo-code:
Which allows you to vary the way that MyView is rendered,
without having to create variants of it:
Usage
You can specify a theme on components which have (or are) a
Context e.g. Activity or Views/ViewGroups:
You can also set a theme in code by wrapping an existing
Context with a ContextThemeWrapper which you could then use to inflate a layout
etc.
The power of themes really comes from how you use them; you
can build more flexible widgets by referencing theme attributes. Different
themes provide concrete values at a later time. For example, you might wish to
set a background color on a section of your view hierarchy:
Rather than setting a static color (#ffffff or a @color
resource) we can delegate to the theme by using the ?attr/themeAttributeName
syntax. This syntax means: query the theme for the value of this semantic
attribute. This level of indirection allows us to provide different behavior
(e.g. providing a different background color in light and dark themes) without
having to create multiple layouts or styles which are mostly identical but for
a few color variations. It isolates the elements that are changing within the
theme.
Use the ?attr/themeAttributeName syntax to query the theme
for the value of this semantic attribute
Scope
A Theme is accessed as a property of a Context and can be
obtained from any object which is or has a Context e.g. Activity, View or
ViewGroup. These objects exist in a tree, where an Activity contains ViewGroups
which contain Views etc. Specifying a theme at any level of this tree cascades
to descendent nodes e.g. setting a theme on a ViewGroup applies to all the
Views within it (in contrast to styles which only apply to a single view).
This can be extremely useful, say if you want a dark themed
section of an otherwise light screen. Read more about this behavior in the next
post (coming soon!).
Note that his behavior only applies at layout inflation time.
While Context offers a setTheme method, or Theme offers an applyStyle method,
these need to be called before inflation. Setting a new theme or applying a
style after inflation will not update existing views.
Separate Concerns
Understanding the different responsibilities and the
interaction of styles and themes, helps to keep your styling resources more
manageable.
For example, say you have a blue theme for your app, but
some Pro screens get a fancy purple look and you want to provide dark themes
with tweaked colors. If you tried to achieve this using only styles, you would
have to create 4 styles for the permutations of Pro/non-Pro and light/dark. As
styles are specific to a type of view (Button, Switch etc) you’d need to create
these permutations for each view type in your app.
Exploding permutations of widgets/styles without theming
If instead we use styles and themes we can isolate the parts
which alter by theme as theme attributes so we only need to define a single
style per view type. For the above example we might define 4 themes which each
provide different values for the colorPrimary theme attribute, which these
styles then refer to and automatically reflect the correct value from the
theme.
This approach might seem more complicated as you need to
consider the interaction of styles and themes, but it has the benefit of
isolating the parts that change per theme. So if your app rebrands from blue to
orange, you only need to change this in a single place, not scattered
throughout your styling. It also helps fight a proliferation of styles. Ideally
you only have a small number of styles per view type. If you don’t take
advantage of theming, it’s easy for your styles.xml file to get out of hand and
explode with different variations of similar styles, which becomes a
maintenance
headache.[Source]-https://medium.com/androiddevelopers/android-styling-themes-vs-styles-ebe05f917578
Enroll for Android Certification in Mumbai at Asterix
Solution to develop your career in Android. Make your own android app after Android Developer Training provides under the guidance of expert Trainers.
Comments
Post a Comment