Customize your Garmin Watchface with Settings
A guide on how to integrate settings to your garmin watchface
In my previous article Build your own Garmin Watchface I wrote about how to get started with the watchface development on garmin devices. Now it is time to make the watchface customizable with some settings. I recommend reading the first article before continuing here, since it will cover the basics that we will need here.
Why we need Settings
The answer to that is straight forward. Not everybody wants to have the same look or data on their watch. Settings can create a unique user experience for your watchface. That also makes it great for a wide range of users to use your watchface to use your watchface, since everyone can customize it to their needs.
In theory, everything can be customized though settings. For example, you can customize data fields or colors or even layouts. Everything is possible and only your creativity is the limit.
Implement Settings
Now let's start directly with the implementation of settings. I will only cover some basic examples of how to implement settings. If you got some questions regarding more complex examples haven't hesitate to write to me and ask me directly.
Settings folder
To integrate settings we need to add a new folder resources/settings
to our project. This folder will contain two files. The properties.xml
file wich contains all properties of your watchface and also the default configuration that is enabled on first startup. And also the settings.xml
file wich contains the layout for the user interface in the Garmin Connect IQ App.
properties.xml
For now, we will implement three simple settings for our watchface. A customizable title, an option if something should be shown and an option for what should be shown. For that we need to update our properties.xml
to look like the following file. In the configuration, we add a property for every setting we need and set the corresponding data type. For example, our title is a string and our option if something should be displayed is a boolean.
<properties>
<property id="Title" type="string">Hello</property>
<property id="ShowBottom" type="boolean">true</property>
<property id="DisplayOption" type="number">0</property>
</properties>
settings.xml
Now the properties wich we already setup in the previous step needs a settings configuration that reflects the user interface in the Connect IQ App. This file will also include titles for the settings and more. Let's have a look at the settings file that reflects our properties.
<settings>
<setting propertyKey="@Properties.Title" title="@Strings.Title">
<settingConfig type="alphaNumeric" />
</setting>
<setting propertyKey="@Properties.ShowBottom" title="@Strings.ShowBottom">
<settingConfig type="boolean" />
</setting>
<setting propertyKey="@Properties.DisplayOption" title="@Strings.DisplayOption">
<settingConfig type="list">
<listEntry value="0">@Strings.None</listEntry>
<listEntry value="1">@Strings.Blue</listEntry>
<listEntry value="2">@Strings.Green</listEntry>
</settingConfig>
</setting>
</settings>
As you see for every property we add a setting with the corresponding propertyKey pointing to the property with @Properties.*
and a title for the setting wich is a string from our strings.xml
file. Inside of the setting tag we implement the configuration for the setting with the data type. Now we also see the type for our DisplayOption
property. Here we use a list type wich will result in a easy to use select box for the user. For every option in this select box we implement a listEntry wich a value wich we will use in the code and a string to be readable to the user.
As you see, for every property we add a setting with the corresponding propertyKey
pointing to the property with @Properties.*
and a title for the setting, which is a string from our strings.xml
file. Inside of the setting tag we implement the configuration for the setting with the data type. Now we also see the type of our DisplayOption
property. Here we use a list type which will result in an easy to use select box for the user. For every option in this select box we implement a listEntry
which is a value which we will use in the code and a string to be readable to the user.
Since we used @Strings.*
in this file we need to add these string in the strings.xml
file and our new strings file will look like this.
<strings>
<string id="AppName">example</string>
<string id="Current">CURRENT</string>
<string id="Title">Custom Title</string>
<string id="ShowBottom">Show bottom data</string>
<string id="DisplayOption">Select color</string>
<string id="None">None</string>
<string id="Blue">Blue</string>
<string id="Green">Green</string>
</strings>
Usage in code
The previous steps enabled the user to select the settings and customize them. Now we need to implement these settings in the code to react correct to the settings. Let't do that one at a time to understand the basics.
First lets habe a look at our current implementation of our onUpdate()
function since that is the place where we need to implement the settings.
// Update the view
function onUpdate(dc as Dc) as Void {
// Get and show the current time
var clockTime = System.getClockTime();
var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
var view = View.findDrawableById("TimeLabel") as Text;
view.setText(timeString);
// Get and show the current step count
var stepCount = ActivityMonitor.getInfo().steps;
System.println(stepCount);
var displayedSteps = stepCount == null ? 0 : stepCount;
var stepCountLabel = View.findDrawableById("StepCount") as Text;
stepCountLabel.setText(displayedSteps.toString());
// Call the parent onUpdate function to redraw the layout
View.onUpdate(dc);
}
Now let's change the code so that we update the title of our watchface to the settings title. To do this we need to add an id="Title"
to the label in our layout.xml
since we want to access it just like we do with the other labels.
<!-- ... -->
<label id="Title" text="@Strings.Current" x="center" y="25%" font="Graphics.FONT_XTINY" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_RED" />
<!-- ... -->
Now we are able to access the label and replace it with our setting.
// Update the view
function onUpdate(dc as Dc) as Void {
// get title label and replace with setting
var titleLabel = View.findDrawableById("Title") as Text;
var titleSetting = Application.Properties.getValue("Title") as Lang.String;
titleLabel.setText(titleSetting);
// ...
}
You can see that we access the title setting with Application.Properties.getValue("Title")
. The same way, we could also set the setting from within the code if we need it with the function Application.Properties.setValue("Title", "New Value")
. Since we now know how to do it, let's also use the setting for boolean on the bottom data.
// Update the view
function onUpdate(dc as Dc) as Void {
// ...
// Get and show the current step count at the bottom
var stepCount = ActivityMonitor.getInfo().steps;
System.println(stepCount);
var displayedSteps = stepCount == null ? 0 : stepCount;
var stepCountLabel = View.findDrawableById("StepCount") as Text;
var showBottom = Application.Properties.getValue("ShowBottom") as Lang.Boolean;
if (showBottom) {
stepCountLabel.setText(displayedSteps.toString());
} else {
stepCountLabel.setText("");
}
// ...
}
In the previous code you can see that we access the ShowBottom
setting. This is used to display the steps on true and display an empty string or also nothing on false. Now the last step is to implement our DisplayOption
setting into the code, which contains a color selection as code.
// Update the view
function onUpdate(dc as Dc) as Void {
// ...
// Get and show the current time
var clockTime = System.getClockTime();
var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
var view = View.findDrawableById("TimeLabel") as Text;
view.setText(timeString);
var displayOption = Application.Properties.getValue("DisplayOption") as Lang.Number;
switch (displayOption) {
case 0: // none
view.setColor(Graphics.COLOR_TRANSPARENT);
break;
case 1: // blue
view.setColor(Graphics.COLOR_BLUE);
break;
case 2: // green
view.setColor(Graphics.COLOR_GREEN);
break;
}
// ...
}
Here you can see that we access the DisplayOption
setting and, depending on the value, we change the color of our label to the selected setting. Our changed code in the onUpdate
function will now look like the following.
// Update the view
function onUpdate(dc as Dc) as Void {
// get title label and replace with setting
var titleLabel = View.findDrawableById("Title") as Text;
var titleSetting = Application.Properties.getValue("Title") as Lang.String;
titleLabel.setText(titleSetting);
// Get and show the current time
var clockTime = System.getClockTime();
var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
var view = View.findDrawableById("TimeLabel") as Text;
view.setText(timeString);
var displayOption = Application.Properties.getValue("DisplayOption") as Lang.Number;
switch (displayOption) {
case 0: // none
view.setColor(Graphics.COLOR_TRANSPARENT);
break;
case 1: // blue
view.setColor(Graphics.COLOR_BLUE);
break;
case 2: // green
view.setColor(Graphics.COLOR_GREEN);
break;
}
// Get and show the current step count at the bottom
var stepCount = ActivityMonitor.getInfo().steps;
System.println(stepCount);
var displayedSteps = stepCount == null ? 0 : stepCount;
var stepCountLabel = View.findDrawableById("StepCount") as Text;
var showBottom = Application.Properties.getValue("ShowBottom") as Lang.Boolean;
if (showBottom) {
stepCountLabel.setText(displayedSteps.toString());
} else {
stepCountLabel.setText("");
}
// Call the parent onUpdate function to redraw the layout
View.onUpdate(dc);
}
Test the Settings
Now it is time to test our changes in the simulator and change some settings to see if everything works like we expected. For that, we start the simulator with F5
in the debug mode and in the menu of the simulator we navigate to File > Edit Persistent Storage > Edit Application Properties data
or we use the shortcut which is Ctrl + P
on Windows. This will open a basic settings window where we are able to change the settings. After changing some settings, we press save and if everything works correctly, we should already see that the watchface will change its design according to our settings.
Conclusion
Now let's wrap up our learning. We need to add the settings files under the folder resources/settings
. First, the properties.xml
, which contains the default configuration for our settings then the settings.xml
, which contains the layout configuration for our settings and all options for select box settings. After that, we can use the settings in the code by accessing them with Application.Properties.getValue("MySetting")
and change the layout according to the value.
If you want to learn more about the properties and settings on Garmin watchfaces, you can read the official documentation here. You can also reach me out if you have further questions or want to know more about other topics. I am always happy to connect with like-minded developers to help each other and create amazing applications together. And just like the last time, I would be happy if you shared your great watchfaces with me if you get them ready and approved in the store.