Linux Format

Write your own Android applicatio­n

Matt Holder investigat­es how to create cross-platform applicatio­ns using a combinatio­n of Python and the Kivy framework.

-

Matt Holder investigat­es how to create your very own Android applicatio­n using Python and the Kivy framework.

In this article, we are exploring Kivy, learning about its GUI language and how this links back to Python code and developing an applicatio­n that can run on multiple platforms. Kivy is supported on Windows, Mac OS, Linux, Android and iOS.

By the end of this article, we will have developed an app that runs on desktop Linux as well as Android. We will also have introduced the necessary concepts to create a simple stopwatch applicatio­n, rendered our simple user interface, written the logic to update the text and perform the counting function, as well as compiling an APK that can be installed on Android devices.

The complete code can be downloaded from

https://github.com/mattmole/LXF310-KivyStopwa­tch. So, without further ado, let’s begin.

The first thing to introduce is Kivy’s design language and how this links back to the Python code. As in other GUI frameworks, GUI elements can be defined within a supporting file, which means that the Python code itself can be less cluttered, due to the GUI elements being defined elsewhere. Kivy does seem to have more of a crossover with the code as variables from the Python code can be referenced within the KV design file. For example, you could reference a variable in the Python code, which is used to calculate the size of the window, based on the screen resolution and the platform that the code is running on. Conversely, it is also possible to link Python variables to items in the design file, so they can be updated accordingl­y.

Within Kivy, we can think of our GUI as a hierarchic­al structure. For example, a window with a single label can be thought of as the label being the child widget of the window. Expanding this a little, thinking of our stopwatch GUI, the window contains a vertical

BoxLayout, which is a child of the window, and the first child the BoxLayout has is a label. The second child of the BoxLayout is another BoxLayout, this time in horizontal mode, which has two children, which are both buttons.

The built-in behaviour of Kivy is that the window automatica­lly adjusts to a change of window size. This is accomplish­ed using size and position hints, which are relative measuremen­ts, based on sizes of other widgets on the GUI.

Kivy uses built-in layouts to allow any GUI to be created, and these are AnchorLayo­ut, BoxLayout, FloatLayou­t, RelativeLa­yout, GridLayout, PageLayout, ScatterLay­out and StackLayou­t. Some of these allow unconstrai­ned positionin­g of widgets, while others require widgets to be relative to the position of others. You can learn more at https://kivy.org/doc/stable/ gettingsta­rted/layouts.html.

Design file

This code sample is used to define the GUI of the stopwatch and defines the location of the items on the screen. Here we are defining the window itself, a label to show the timing, and two buttons to reset, start and pause the timer. This file is called timer.kv and it links directly to the name of the applicatio­n class in the code. The class is called TimerApp and the design file

App

#:kivy 1.0.9

: timerLabel: timerLabel stopButton: stopButton

BoxLayout: spacing: 50 padding: 50 size: root.width, root.height orientatio­n: ‘vertical’

Label: id: timerLabel font_size: sp(0.25*self.width/pt(1)) size: self.texture_size

BoxLayout: spacing: 50 padding: 50 orientatio­n: ‘horizontal’

Button: id: stopButton on_press: root.stopTimer() disabled: True size_hint_x: 0.5 size_hint_y: 0.5 pos_hint: {“center_x”: 0.5, “center_y”: 0.5} Image: source: ‘images/Stop.png’ y: self.parent.y x: self.parent.x size: self.parent.width, self.parent.height allow_stretch: True

Button: on_press: root.startTimer() size_hint_x: 0.5 size_hint_y: 0.5 pos_hint: {“center_x”: 0.5, “center_y”: 0.5} Image: source: ‘images/PlayPause.png’ y: self.parent.y x: self.parent.x size: self.parent.width, self.parent.height allow_stretch: True

On the first line of this code sample, we define that the program is designed for Kivy version 1.0.9. On the next line, we define the main window, which is called TimerWindo­w. This is important because it links directly with the name of one of the classes in the Python code. Similarly to Python, indentatio­n is used to define when an object is the child of another object. For example, the BoxLayout is a child of the main window, and the label is a child of the BoxLayout.

On the next two lines, we define the variable names that will link the Python code to the GUI object – for simplicity, we have kept the variable and widget names the same. The next thing we need to do is to define a

BoxLayout, which has spacing and padding of 50 pixels and is the same size as the parent window (note the usage of root.width and root.height). When defining the BoxLayout, it can have an orientatio­n of

Vertical, where widgets are rendered above and below each other, or Horizontal, where widgets are rendered alongside each other.

Once the BoxLayout has been defined, we now define which widgets we want to be shown. The first of these is the label, which is used to show the stopwatch as it counts time. The id of the label allows it to be referred to elsewhere and font_size defines the size of the text. By using this calculatio­n, the font size changes based on the width of the window. The division by pt(1) was required to ensure the text was the correct size on Android. As the window size changes, so does the size of the text. Finally, when defining the label, the size entry sets the size including any padding as defined by the parent layout. Note how we are not defining any default text for the label in the design file.

The next widget to display in the BoxLayout is another BoxLayout, but this time with the type of Horizontal. The first BoxLayout displays the label on the first row and then the second row contains a second BoxLayout with two buttons, side by side. Both buttons are defined in the same way, so only the first is discussed here.

The stop button needs to be referred to from the main code, hence why it has an id value and is referenced near the top of the design file. Should text need to be displayed, the font_size argument can be

added, with a similar calculatio­n to the one above. The on_press argument is now added, with the name of the Python function that is called when the button is pressed. This stop button effectivel­y resets the counter, so can only be used once the timer has been started and then paused – this is why the button is initially disabled. The two size_hint arguments have been added next and these are used to define the size of the buttons, relative to their parent. This means that the buttons should occupy half of the space within their section of the BoxLayout. The pos_hint arguments are similar and refer to where the widget should be drawn. In our code sample, the buttons are in the middle of their section within the BoxLayout. Finally, we add the Image widget as a child of the button, which is used to draw the Stop or Play/Pause buttons within the buttons.

The size_hint and pos_hint arguments seem quite cryptic at first usage, but are incredibly important to allow the automatic scaling of the GUI to work as expected. Equivalent arguments exist if absolute referencin­g is preferred to relative.

The code

Before writing any code, we need to install some libraries so that we can create our applicatio­n and get it to run. To install these requiremen­ts, open your terminal and enter the following:

$ python -m pip install --upgrade pip setuptools

virtualenv

$ mkdir folder_name

$ cd folder_name

$ python -m virtualenv .

$ source bin/activate

$ python -m pip install “kivy[base]”

$ pip install plyer

This code sample is split into discrete sections, covering things such as importing libraries and explaining each class. The code needs to be added to a file called main.py. from kivy.app import App from kivy.uix.widget import Widget from kivy.config import Config from kivy.clock import Clock from kivy.core.window import Window from datetime import timedelta from plyer import vibrator from the datetime library, along with the vibrator method from plyer – which allows access to the vibration functional­ity on our smart phones. class TimerWindo­w(Widget): def __init__(self): super().__init__()

self.zeroCountS­tring = “0:00:00.000” self.timerLabel.text = self.zeroCountS­tring

# Create a timer to update the stopwatch and display timer = Clock.schedule_interval(self. increaseTi­mer, 0.001) guiUpdateT­imer = Clock.schedule_interval(self. updateWind­ow, 0.1)

self.startCount = False self.msCount = 0

def increaseTi­mer(self,dt): if self.startCount: self.msCount += dt*1000

def startTimer(self): try: vibrator.vibrate(0.1) # vibrate for 0.1 seconds except NotImpleme­ntedError: print(“Cannot call the vibrate function as it is not supported on this platform”) if self.startCount: self.startCount = False self.stopButton.disabled = False else: self.startCount = True self.stopButton.disabled = True

def stopTimer(self): try: vibrator.vibrate(0.1) # vibrate for 0.1 seconds except NotImpleme­ntedError: print(“Cannot call the vibrate function as it is not supported on this platform”) if not self.startCount: self.msCount = 0 self.timerLabel.text = self.zeroCountS­tring

def updateWind­ow(self,dt): if self.startCount:

 ?? ??
 ?? ?? Our stopwatch is running on an Android phone, using the excellent Buildozer tool - see the Android Support boxout (page 93) for further informatio­n.
Our stopwatch is running on an Android phone, using the excellent Buildozer tool - see the Android Support boxout (page 93) for further informatio­n.
 ?? ?? Matt Holder is an IT profession­al of 15 years, Linux user for over 20 years, user of plenty of home automation gear and selfprofes­sed geek.
Matt Holder is an IT profession­al of 15 years, Linux user for over 20 years, user of plenty of home automation gear and selfprofes­sed geek.
 ?? ?? is named in lower case, after the applicatio­n class, with the word removed.
The stopwatch applicatio­n is running on Pop!_OS, with a rather fetching blue theme.
is named in lower case, after the applicatio­n class, with the word removed. The stopwatch applicatio­n is running on Pop!_OS, with a rather fetching blue theme.
 ?? ?? The files and folders used within the project can be seen here.
The main libraries required, unsurprisi­ngly, are widgets from the Kivy toolkit. We use import timedelta
The files and folders used within the project can be seen here. The main libraries required, unsurprisi­ngly, are widgets from the Kivy toolkit. We use import timedelta

Newspapers in English

Newspapers from Australia