Skip to content

Layouts

The NIMMSTA Smart Watch, renowned for its compact screen design, relies on meticulously crafted layouts to effectively present information. These layouts, implemented through XML or Kotlin files, serve as the foundational structure dictating the arrangement of elements on the Smart Watch screen.

At the core of the NIMMSTA Smart Watch experience is its unique capability to receive layouts and dynamically modify them during runtime. This feature not only accommodates user preferences but also facilitates real-time adjustments, enhancing the device's adaptability to changing needs.

Understanding the structure of layouts is crucial for effective management, offering developers and end-users insights into the visual hierarchy and positioning of elements. Expressed through XML or Kotlin, these structures play a pivotal role in shaping the user interface on the Smart Watch.

The Smart Watch's dynamic adaptability is a standout feature explored in this document. By dynamically modifying layouts, the device can respond to changing circumstances and user interactions, ensuring a seamless and responsive user experience.

For developers, this document provides step-by-step guidance on creating, sending, and managing layouts. The focus is on optimizing information presentation and ensuring compatibility with diverse user preferences. Simultaneously, end-users looking to personalize their Smart Watch interface will find valuable insights into the customization possibilities afforded by layout management, allowing for a tailored and intuitive Smart Watch experience. In conclusion, the NIMMSTA Smart Watch layout management system empowers both developers and users, offering a robust framework for creating, sending, and dynamically adapting layouts.

Introduction

This section describes how to create and send a layout to the NIMMSTA Smart Watch.

Layout Basics

This section describes how to create and send a layout to the NIMMSTA Smart Watch.

The functionality of the NIMMSTA Smart Watch relies on a comprehensive layout system to effectively showcase information on its screen. Each layout within this system is uniquely identified by a name and must define the default deviceLayout and screen. This particular configuration is crucial for enabling flexible reuse of layouts, especially as the Smart Watch market evolves and introduces multiple device variations. up until version 7.0.5, the system supports only one screen per layout, however since version 7.0.5 You can directly use StaticElements inside NimmstaLayout.

Layouts in the NIMMSTA Smart Watch can be defined either in Kotlin code or as XML. If you opt for XML, the NIMMSTA Core Library seamlessly inflates your layout to objects of the respective class instances. The subsequent samples will guide you through the process of designing and laying out the screen on the NIMMSTA Smart Watch, providing insights into the intricacies of both Kotlin and XML approaches.

Info

It's important to note that if you are not utilizing the NIMMSTA Core Library for your application development, your access will be limited to XML layouts. This distinction is vital for developers who may choose alternative libraries or frameworks, emphasizing the versatile nature of the NIMMSTA Smart Watch layout system.

Dimensions & Screen

The Smart Watch screen has a resolution of 200px x 200px and a diameter of 1.54 inches (3.91 cm). As this is not a big screen you have to think about the most important part of your application and how to save space.

Another thing to keep in mind is that the NIMMSTA Smart Watch has a whitepaper display. While this saves power and therefore enables great battery life, it also has a long update time. It is normal for the screen to take roughly 0.5-1.0 seconds until it is refreshed.

Static layouts

Currently, the layout is evaluated on the client side and then sent over to the NIMMSTA Smart Watch. You should change the screen as rarely as possible to improve the user-felt responsiveness.

The layout itself is based on a static layout system. Every element is statically placed on the screen.

Boilerplate and screen definition

To know which screen and device is targeted by a specific layout and for future adaptability, we define which device and screen size is used for each layout. An empty layout looks like the one below. We will use it in the later examples.

val layout = NimmstaLayout { 
    name = "empty"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {

                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="empty">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <!-- The elements are going to be placed here -->
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

Fonts

Currently, we support the Bahnschrift_SemiBold, Bahnschrift_SemiLight, and LiberationMono fonts.

Info

Please be aware that since the device manages spacing internally, the font is not monospace anymore.

The fonts support all printable ASCII characters. Additionally, the following characters are available:

  • Ä, ä, Ö, ö, Ü, ü, ß, €, £, ¥

Elements

All elements share some basic properties to position them.

  • x (X position on the screen)
  • y (Y position on the screen)
  • width (Width of the element)
  • height (Height of the element)

Elements update automatically when you update one of their properties.

When you don't set these values, our layouting system will automatically assign a specific frame to each of the properties like this:

  • When x is null, it will assign 0
  • When y is null, it will assign the previous sibling1 view's y + the previous sibling view's height
  • When width is null, it will assign the width of the screen - x
  • When height is null, it will assign the intrinsic height of the view, e.g. for text this is equal to the line height.

Additionally, all elements have the following attributes:

  • name (Name of the cell to find them within a layout or name of an icon)
  • value (Text to be displayed)

In the following subsections, we will provide information about the basic types.

Cell

Cell is the main element type used for single-line text. It provides a value, which corresponds to the text that can be displayed. Currently, roughly 23 characters of small text, depending on which characters, can fit in one line (using the default font size).

It also supports wrapping of text, automatic font sizing and multi lines.

  • fontSize (Unit: pt) Default: 17pt
    • auto
    • 11pt
    • 17pt
    • 22pt
    • 26pt
    • 30pt
    • 34pt
    • 40pt
    • 52pt
  • fontFamily (Unit: pt) Default: LiberationMono
    • LiberationMono
    • Bahnschrift_SemiBold (Since 5.3)
    • Bahnschrift_SemiLight (Since 5.3)
  • characterSpacing (Unit: px) Default: 1px
  • textColor Default: BLACK
    • NONE
    • BLACK
    • WHITE
    • AUTO_INVERTED (Automatically uses the complement color of the background)
  • padding (Unit: pt) Adds padding around the text Default: 0px (Since 5.3)
  • backgroundColor (Unit: pt) Changes the background color Default: White (Since 5.3)
    • BLACK
    • WHITE
    • AUTO_INVERTED (Automatically uses the complement color of the background)
  • horizontalAlignment Default: START
    • START (left)
    • CENTER
    • END (right)
    • BLOCK (spacing between words is chosen to fill entire line)
  • verticalAlignment Default: START
    • START (top)
    • CENTER
    • END (bottom)
    • BLOCK (spacing between words is chosen to fill entire line)
  • wrapMode Defines if lines that are longer than the screen will wrap around to the next line Default: NO_WRAP
    • WRAP
    • NO_WRAP
  • lineHeight (Unit: %) Default: 110%
  • maxLines Defines the maximum amount of lines, other lines are cut off (values less than or equal to 0 mean unlimited lines) Default: 1
val layout = NimmstaLayout {
    name = "twoCells"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {
                    cell {
                        name = "mycell"
                        x = 10.0
                        y = 10.0
                        value = "mycell"
                    }
                    cell {
                        name = "myBigcell"
                        y = 40.0
                        horizontalAlignment = Alignment.CENTER
                        maxLines = 0
                        wrapMode = WrapMode.WRAP
                        fontSize = 34.pt
                        value = "myBigCell"
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="twoCells">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <cell x="10" y="10" name="mycell" />
                <!-- maxLines = 0 means it will allow unlimited lines -->
                <cell y="40" horizontalAlignment="center" maxLines="0" wrapMode="wrap" name="myBigcell" fontSize="34pt" />                  
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

Icon

Represents a specific icon on the screen of the NIMMSTA Smart Watch. Currently the Icons provided are limitted to specific icons and sizes.

Icon Name Dimensions
error_cross 60x60px
success_tick 60x60px
nimmsta_logo 180x180
CONNECTED 30x23
SCAN_NOW 93x60
SCAN_NOW_WITHOUT_TOUCH 139x100
SCAN_NOW_TOUCH 139x100
  • error_cross of size 60x60px
  • success_tick of size 60x60px
  • nimmsta_logo of size 180x180px
val layout = NimmstaLayout {
    name = "icons"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {
                    icon {
                        x = 10.0
                        y = 10.0
                        name = "error_cross"
                    }
                    icon {
                        x = 10.0
                        y = 65.0
                        name = "success_tick"
                    }
                    icon {
                        x = 10.0
                        y = 70.0
                        name = "nimmsta_logo"
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="icons">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <icon x="10" y="10" name="error_cross" />
                <icon x="10" y="65" name="success_tick" />
                <icon x="10" y="70" name="nimmsta_logo" />
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

ScanResult

ScanResult is a specific view that automatically shows the last scanned barcode or will show the default text.

  • timeToShowBarcode How many seconds the result will be shown. If null the result will be displayed until it is overwritten. Default: null
  • applyRule Defines if the barcode rules should be applied before displaying the barcode on the screen. If set to false the barcode will be displayed as scanned, without applying the rules first. Default: false
  • fontSize (Unit: pt) Default: 17pt - 11pt - 17pt - 26pt - 30pt - 34pt - 40pt - 52pt
  • characterSpacing (Unit: px) Default: 1px
  • textColor Default: BLACK
    • NONE
    • BLACK
    • WHITE
    • AUTO_INVERTED (Automatically uses the complement color of the background)
  • horizontalAlignment Default: START
    • START (left)
    • CENTER
    • END (right)
    • BLOCK (spacing between words is chosen to fill entire line)
  • verticalAlignment Default: START
    • START (top)
    • CENTER
    • END (bottom)
    • BLOCK (spacing between words is chosen to fill entire line)
  • wrapMode Defines if lines that are longer than the screen will wrap around to the next line Default: NO_WRAP
    • WRAP
    • NO_WRAP
  • lineHeight (Unit: %) Default: 110%
  • maxLines Defines the maximum amount of lines, other lines are cut off (values less than or equal to 0 mean unlimited lines) Default: 1
val layout = NimmstaLayout {
    name = "scanResults"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {
                    cell {
                        x = 10.0
                        y = 10.0
                        value = "Scan Now"
                    }
                    scanResult {
                        x = 10.0
                        timeToShowBarcode = 10
                        value = "Will show barcode 10s"
                        wrapMode = WrapMode.WRAP
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="scanResults">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <cell x="10" y="10">Scan Now</cell>
                <scanresult x="10" timeToShowBarcode="10" wrapMode="wrap">Will show barcode 10s</scanresult>
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

Button

Buttons represent a touchable button on the screen. Each Button will automatically trigger the vibrator of the device once recognized and will fire a ButtonClickEvent, which will automatically call the didClickButton method.

  • shouldTriggerVibratorOnClick Defines if the vibrator should be triggered when the button is clicked. Default: true
  • padding Padding to be applied to the button. Will set paddingLeft, paddingRight, paddingTop and paddingBottom. If you want to set the padding values individually, don't use this property. Default: 5.0
  • paddingLeft Default: 5.0
  • paddingRight Default: 5.0
  • paddingTop Default: 5.0
  • paddingBottom Default: 5.0
  • type Defines the primary style of the button including the fill color, text color, 3D and rounding. Default: INVERTED3D_ROUNDED
    • PLAIN
    • PLAIN_ROUNDED
    • BUTTON3D
    • BUTTON3D_ROUNDED
    • INVERTED
    • INVERTED_ROUNDED
    • INVERTED3D
    • INVERTED3D_ROUNDED
  • fontSize (Unit: pt) Default: 17pt
    • 11pt
    • 17pt
    • 26pt
    • 30pt
    • 34pt
    • 40pt
    • 52pt
  • characterSpacing (Unit: px) Default: 1px
  • textColor Default: BLACK
    • NONE
    • BLACK
    • WHITE
    • AUTO_INVERTED (Automatically uses the complement color of the background)
  • horizontalAlignment Default: START
    • START (left)
    • CENTER
    • END (right)
    • BLOCK (spacing between words is chosen to fill entire line)
  • verticalAlignment Default: START
    • START (top)
    • CENTER
    • END (bottom)
    • BLOCK (spacing between words is chosen to fill entire line)
  • wrapMode Defines if lines that are longer than the screen will wrap around to the next line Default: NO_WRAP
    • WRAP
    • NO_WRAP
  • lineHeight (Unit: %) Default: 110%
  • maxLines Defines the maximum amount of lines, other lines are cut off (values less than or equal to 0 mean unlimited lines) Default: 1
val layout = NimmstaLayout {
    name = "buttons"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {
                    button {
                        x = 0.0
                        y = 10.0
                        horizontalAlignment = Alignment.CENTER
                        width = 100.0
                        height = 50.0
                        name = "increment"
                        value = "+"
                    }
                    button {
                        x = 100.0
                        y = 10.0
                        horizontalAlignment = Alignment.CENTER
                        width = 100.0
                        height = 50.0
                        name = "decrement"
                        value = "-"
                    }
                    button {
                        x = 50.0
                        width = 110.0
                        name = "next_task"
                        value = "Next Task"
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="buttons">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <!-- you can use spaces if the + otherwise would be on the left -->
                <button x="0" y="10" horizontalAlignment="center" width="100" height="50" name="increment">+</button>
                <button x="100" y="10" horizontalAlignment="center" width="100" height="50" name="decrement">-</button>
                <button x="50" width="110" name="next_task">Next Task</button>
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

Event Handler:

override fun didClickButton(device: NIMMSTADevice, sender: Button?, event: ButtonClickEvent) {

    when(sender?.name) {
        "decrement" -> { /* decrement */ }
        "increment" -> { /* increment */ }
        "next_task" -> { /* next task */ }
    }
}
@Override
public void didClickButton(@NotNull NIMMSTADevice nimmstaDevice, @Nullable Button button, @NotNull ButtonClickEvent buttonClickEvent) {
    if (button != null) {
        switch (Objects.requireNonNull(button.getName())) {
            case "decrement" -> { /* decrement */ }
            case "increment" -> { /* increment */ }
            case "next_task" -> { /* next task */ }
        }
    }
}

Status Bar

The standard status bar for devices. It consists of a connected indicator, the battery-level, the battery icon and the charging icon. By default, the status bar will be placed in the upper left-hand corner with a height of 28px.

Since Release 6.0, we also support custom text within the Status Bar. If not set, it will show the type of the imager.

statusBar {
    value = "Custom" // supported since 6.x
}
<statusBar />
<!-- supported since 6.x -->
<statusBar>Custom</statusBar>

Battery

Shows the battery icon.

battery {
    y = 6.0
}
<battery y="6.0" />

Battery Percent

Shows the battery percent in decimal (0-100%).

batteryPercent {
    x = 115.0
    y = 10.0
}
<batteryPercent x="115.0" y="10.0" />

Horizontal Line

Horizontal lines need to have a defined width. The height can only be 1.0 or 2.0.

horizontalLine {
    x = 10.0
    y = 130.0
    width = 180.0
    height = 1.0
}
<horizontalLine x="10.0" y="130.0" width="180.0" height="1.0" />

Vertical Line

Vertical lines need a to have a defined height. The width can only be 1.0 or 2.0.

verticalLine {
    x = 10.0
    y = 0.0
    width = 1.0
    height = 180.0
}

<verticalLine x="10.0" y="0.0" width="1.0" height="180.0" />
````

Updating layout values

Once a layout is sent to the NIMMSTA Smart Watch, it's good practice to update it instead of sending completely new layouts to the NIMMSTA Smart Watch. The differential approach leads to faster updates and better user experience. For most common cases, it's enough to update just layout values, which means you provide a map of key-value pairs, where keys are the names of the elements and value are the new value properties of the elements. In the following example we consider a layout like this one:

val layout = NimmstaLayout {
    name = "updating"
    deviceLayouts {
        deviceLayout {
            screen {
                name = "default"
                isDefaultScreen = true
                staticElements {
                    cell {
                        name = "title"
                        value = "Default Title"
                    }
                    cell {
                        name = "subtitle"
                        value = "Default Subtitle"
                    }
                }
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<NimmstaLayout name="updating">
    <device width="1.54" height="1.54" pxx="200" pxy="200">
        <screen default="true" name="default">
            <staticElements>
                <cell name="title">Default Title</cell>
                <cell name="subtitle">Default Subtitle</cell>
            </staticElements>
        </screen>
    </device>
</NimmstaLayout>

If we want to update one field, we can do it like this:

Info

If you are not using the NIMMSTA Core Library to develop your application, refer to the specific UpdateLayout command in the documentation of the respective library.

device.setScreenInfoAsync(
    hashMapOf(
        "title" to "new title"
    )
).onSuccess {
    Log.d("NIMMSTA", "Success setting layout variables")
}.onError {
    Log.d("NIMMSTA", "Error setting layout $it")
}
HashMap<String, String> map = new HashMap<String, String>();  
map.put("title", "new title");
device.setScreenInfoAsync(map);

Pushing a new layout

To push a new layout to the NIMMSTA Smart Watch, there is the setLayout API. You need to read XML files yourself.

Info

If you are not using the NIMMSTA Core Library to develop your application, refer to the specific SetLayout command in the documentation of the respective library.

This function will invoke the async onSuccess event handler once the screen was refreshed. If another setLayout is called before that, it will invoke onError with a CancellationException.

class ExampleEventHandler: NIMMSTAEventHandler {
    /* ... */

    override fun didConnectAndInit(device: NIMMSTADevice) {
        device.setLayout("<?xml ...")
        // if you want to add variables already
        device.setLayout("<?xml ...", mapOf(
            "variable1" to "foo"
        )).onSuccess {
            Log.d("NIMMSTA", "Success setting layout")
        }.onError {
            Log.d("NIMMSTA", "Error setting layout $it")
        }
    }
}
class ExampleEventHandler implements NIMMSTAEventHandler {
    /* ... */

    @Override
    public void didConnectAndInit(NIMMSTADevice nimmstaDevice) {
        nimmstaDevice.setLayout("<?xml ...");
        // if you want to add variables already
        HashMap<String, String> map = new HashMap<String, String>();  
        map.put("title", "new title");
        nimmstaDevice.setLayout("<?xml ...", map);
    }

    /* ... */
}

  1. The previous sibling view is the view above the current view in XML. For example, if you have three views under StaticElements A, B and C. The previous sibling of C is B, and the previous sibling of B is A.