At the time of writing this, the flat design paradigm is trending in the interface design field, systematically taking over every platform, be it Web, mobile, or desktop. Prominent examples of this paradigm shift in the wild are iOS 7 and later and Windows 8 and later. Internet companies followed suit with the "Material design principles" presented at Google I/O 2014 conference, along with many other HTML5 frameworks, including the well-established ones, for example, Bootstrap.
Conveniently, the flat design emphasizes content over presentation, omitting photo-realistic shadows and detailed textures in favor of plain colors and simple geometry. It is by all means simpler to create programmatically than the "old school" skeuomorphic design that tends to be visually rich and artistic.
Note
Skeuomorphism is a common approach to user interface design. It is characterized by applications visually imitating their real-world counterparts, for example, a Calculator app with the same button layout and look and feel as a cheap physical calculator. This may or may not help user experience (depending on who you ask).
Giving up visual details in favor of a simpler, more streamlined interface seems to be the direction everyone is going in today. On the other hand, it's naturally challenging to build a distinctive, memorable interface just from colored rectangles and such. This is why the flat design is typically synonymous with good typography; depending on the application, text is almost always a significant part of the UI, so we want it to look great.
Imitation is the sincerest form of flattery, and we will imitate the clock design from Android 4.1 Jelly Bean. The distinctive feature of this design is the font weight contrast. Until it was changed in version 4.4 KitKat, the default clock used to look like this:
The font used is Roboto, Google's Android font that superseded the Droid font family in Android 4.0 Ice Cream Sandwich.
Roboto is free for commercial use and available under the permissive Apache License. It can be downloaded from Google Fonts or from the excellent Font Squirrel library at http://www.fontsquirrel.com/fonts/roboto.
When it comes to the typography, Kivy defaults to Droid Sans—Google's earlier font. It's easy to replace Droid with a custom font, as Kivy allows us to specify the font_name
property for textual widgets (in this case, Label
).
In the simplest case when we have just one font variant, it is possible to assign a .ttf
filename directly in the definition of a widget:
For the aforementioned design, however, we want different font weights, so this approach won't cut it. The reason being, every variation of a font (for example, bold or italic) commonly lives in a separate file, and we can only assign one filename to the font_name
property.
Our use case, involving more than one .ttf
file, is better covered by a LabelBase.register
static method. It accepts the following arguments (all optional), exemplified by the Roboto font family:
After this invocation, it becomes possible to set the font_name
property of a widget to the name of the previously registered font family, Roboto
in this case.
This approach has two limitations to be aware of:
- Kivy only accepts TrueType
.ttf
font files. If the fonts are packaged as OpenType .otf
or a web font format such as .woff
, you may need to convert them first. This can be easily done using the FontForge editor, which can be found at http://fontforge.org/. - There is a maximum of four possible styles per font: normal, italic, bold, and bold italic. It's fine for older font families, such as Droid Sans, but many modern fonts include anywhere from 4 to over 20 styles with varying font weight and other features. Roboto, which we're going to use shortly, is available in at least 12 styles.
The second point forces us to choose which font styles we will use in our application as we can't just throw in all 12, which is a bad idea anyway as it would lead to a hefty increase in file size, up to 1.7 megabytes in the case of Roboto family.
For this particular app, we only need two styles: a lighter one (Roboto-Thin.ttf
) and a heavier one (Roboto-Medium.ttf
), which we assign to fn_regular
and fn_bold
respectively:
This code should be placed right after the __name__ == '__main__'
line in main.py
, as it needs to run before the interface is created from the Kivy language definition. By the time the app class is instantiated, it might already be too late to perform basic initialization like this. This is why we have to do it in advance.
Now that we have a custom font in place, all that's left is to assign it to our Label
widget. This can be done with the help of the following code:
The most popular and universally used markup language out there is undoubtedly HTML. Kivy, on the other hand, implements a variant of BBCode, a markup language once used to format posts on many message boards. Visible distinction from HTML is that BBCode uses square brackets as tag delimiters.
The following tags are available in Kivy:
Tip
This is by no means an exhaustive reference because Kivy is under active development and has probably undergone a number of releases since this text was written, adding new features and refining the existing functionality. Please refer to the Kivy documentation found on the official website (http://kivy.org) for an up-to-date reference manual.
Let's return to our project. To achieve the desired formatting (hours in bold and the rest of the text in fn_regular
thin font), we can use the following code:
Kivy's BBCode flavor works only if we also set the markup
property of a widget to True
, as shown in the preceding code. Otherwise, you will literally see the string [b]…[/b]
displayed on the screen, and that's clearly not desired.
Note that if we wanted to make the whole text bold, there is no need to enclose everything in [b]…[/b]
tags; we could just set the bold
property of the widget to True
. The same applies to italic, color, font name, and size—pretty much everything can be configured globally to affect the whole widget without touching markup.
Changing the background color
In this section, we will adjust the window background color. Window background (the "clear color" of OpenGL renderer) is a property of a global Window
object. In order to change it, we add this code right after the __name__ == '__main__'
line in main.py
:
The get_color_from_hex
function is not strictly required, but it's nice as it allows us to use CSS-style (#RRGGBB
) colors instead of (R, G, B)
tuples throughout our code. And using CSS colors is preferable for at least the following two reasons:
- Less cognitive overhead when reading: The
#FF0080
value is immediately recognized as a color when you're familiar with this notation, while (255, 0, 128) is just a bunch of numbers that may be used differently depending on the context. The floating-point variant of #FF0080
, (1.0, 0.0, 0.50196) is even worse. - Simple and unambiguous searching: A tuple can be arbitrarily formatted, while a CSS-like color notation is uniform, albeit case-insensitive. Performing a case-insensitive search in most text editors is very simple, as opposed to locating all instances of a given tuple inside a lengthy Python listing. The latter task can prove challenging and involve regular expressions, among other things, because the formatting of tuples doesn't have to be consistent.
We will talk more about design-related features of Kivy later on. Meanwhile, let's make our application actually show the time.