View Components Guide
chevron down
 

View Components Guide

Cycle View

The cycleview component allows developers to display a single item from a list. When the user taps the item, the current item slides upwards and is replaced with the next item from the list. When the end of the list is reached, the first item is displayed, starting the loop again.

First you need to declare a cycleview element as a container. By default it will have a height and width of 100%.

Then you must declare one or more cycleview-item elements, which will contain the actual content you wish to cycle.

Imports

In addition to any existing imports, you must include the following imports within your widgets.gui file:

<svg viewport-fill="fb-green">
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui" />
    <!-- Additional Imports -->
    <link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/cycleview_widget.gui" />
  </defs>
</svg>

Usage

The following example will display 5 different statistics which will be displayed in one at a time, tap the item to cycle to the next statistic.

Include the following SVG in your index.gui file:

<svg>
  <use id="stats-cycle" href="#cycleview">
    <use href="#cycleview-item" class="cycle-item">
      <text>Steps: 1,337</text>
    </use>
    <use href="#cycleview-item" class="cycle-item">
      <text>Calories: 731</text>
    </use>
    <use href="#cycleview-item" class="cycle-item">
      <text>Distance: 1.00mi</text>
    </use>
    <use href="#cycleview-item" class="cycle-item">
      <text>Floors: 10</text>
    </use>
    <use href="#cycleview-item" class="cycle-item">
      <text>Active: 13</text>
    </use>
  </use>
</svg>

Include the following CSS in your styles.css file:

.cycle-item text {
  font-size: 32;
  font-family: System-Regular;
  font-weight: regular;
  text-length: 32;
  fill: white;
  x: 100%-10;
  text-anchor: end;
}

Panorama View

The panoramaview component allows developers to create applications which have a horizontal scrolling tiles, similar to the Fitbit Exercise application. Pagination dots are used to indicate how many tiles are available, and which tile is currently selected.

First you need to declare a panoramaview element as a container. By default it will have a height and width of 100%.

Then you must declare one or more panoramaview-item elements, which will contain the actual content you wish to scroll.

Imports

In addition to any existing imports, you must include the following imports within your widgets.gui file:

<svg>
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui" />
    <!-- Additional Imports -->
    <link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/panoramaview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/pagination_dots.gui" />
  </defs>
</svg>

Usage

The following example will display 4 rect elements which will be displayed in a list which can be scrolled by swiping horizontally.

Include the following SVG in your index.gui file:

<svg>
  <use id="container" href="#panoramaview">
    <use id="item1" href="#panoramaview-item">
      <rect width="100%" height="100%" fill="red" />
    </use>
    <use id="item2" href="#panoramaview-item">
      <rect width="100%" height="100%" fill="green" />
    </use>
    <use id="item3" href="#panoramaview-item">
      <rect width="100%" height="100%" fill="blue" />
    </use>
    <use id="item4" href="#panoramaview-item">
      <rect width="100%" height="100%" fill="gray" />
    </use>

    <!-- Have enough pagination dots for your slides (extras are hidden) -->
    <use id="pagination-dots" href="#pagination-widget" y="8">
      <use href="#pagination-dot" />
      <use href="#pagination-dot" />
      <use href="#pagination-dot" />
      <use href="#pagination-dot" />
      <use href="#pagination-dot" />
      <use href="#pagination-highlight-dot" />
    </use>
  </use>
</svg>

If you don't want the pagination dots, you can remove the pagination_dots.gui from your widgets.gui, and exclude the pagination-dots element from your index.gui file.

JavaScript

You can use the value property to get and set the selected zero-based index of the panoramaview in JavaScript.

import document from "document";

let container = document.getElementById("container");

// Get the selected index
let currentIndex = container.value;

// Set the selected index
container.value = 0; // jump to first slide

The SELECT event is not currently available, so it's not possible to detect when a user selects a different tile.

Configuration

The component is composed of the following SVG sub elements:

  • #panoramaview-item: A repeating container element within the panorama.

Scroll View

The scrollview component allows developers to create an application which is taller than the screen dimensions. The user can easily scroll the entire view vertically with their finger.

First you need to declare a scrollview element as a container. By default it will have a height and width of 100%.

Then you must declare one or more scrollview-item elements, which will contain the actual content you wish to scroll. Each item has a height property, which by default will be 100% of the scrollview container element height.

Imports

In addition to any existing imports, you must include the following imports within your widgets.gui file:

<svg>
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui" />
    <!-- Additional Imports -->
    <link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/scrollview_widget.gui" />
  </defs>
</svg>

Usage

The following example will display 3 images which will be displayed in a vertical list which can be scrolled.

Include the following SVG in your index.gui file:

<svg>
  <use href="#scrollview">
    <use href="#scrollview-item">
      <image href="01.png" />
    </use>
    <use href="#scrollview-item">
      <image href="02.png" />
    </use>
    <use href="#scrollview-item">
      <image href="03.png" />
    </use>
  </use>
</svg>

Section Headers

You can also create multiple section of items, with a header that snaps to the top of the screen. When all of the items for a section have been scrolled, the next header snaps to the top of the screen.

This example uses a reusable template symbol. If you're unfamiliar with them, we recommend taking a look at the Template Symbol section of the SVG guide.

<svg>
  <defs>
    <!-- Template Symbol for the header -->
    <symbol id="view-header" href="#scrollview-header">
      <rect fill="inherit" x="0" y="0" width="100%" height="100%"/>
      <text id="text" x="5" y="50%+10" fill="black" font-size="30"
        font-weight="bold" />
    </symbol>
  </defs>
  <use href="#scrollview">
    <!-- Section 1 -->
    <use href="#view-header" height="40" fill="pink">
      <set href="#text" attributeName="text-buffer" to="Section 1" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-red" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-blue" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-cyan" />
    </use>
      <!-- Section 2 -->
    <use href="#view-header" height="40" fill="fb-peach">
      <set href="#text" attributeName="text-buffer" to="Section 2" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-red" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-blue" />
    </use>
    <use href="#scrollview-item">
      <rect width="100%" height="250" fill="fb-cyan" />
    </use>
  </use>
</svg>

Configuration

The component is composed of the following SVG sub elements:

  • #scrollview-header: A container element for a section heading.

  • #scrollview-item: A repeating container element within the scrollview.

Tile List

The tile-list component allows developers to create an application which provides users the ability to vertically scroll a list of tile-list-item elements.

Although similar to the Scroll View, there are some subtle differences, for example:

  • The height of a Tile Item should not exceed the height of the screen.

  • Tile Items can be dynamically reordered using drag and drop.

  • When scrolling, the Tile List can automatically snap to the top of the closest Tile Item.

First you need to declare a tile-list element as a container. By default it will have a height and width of 100%.

Then you must declare one or more tile-list-item elements, which will contain the actual content you wish to scroll. Each item is 100% height. You can mix different elements inside a tile element.

You can also have a header by using the tile-list-header element. Headers behave the same way as a tile-list-item, except that a header cannot be selected for reorder, and a reordered item cannot be dragged over a header. A list can have any number of header tiles.

Last, but not least, you can add a footer using the tile-list-footer element. If a list has a footer, there may only be one, and it must be the last entry in the list. A footer tile cannot be selected for reorder, and a reordered item cannot be dragged over the footer. If the user drags the list upwards, the footer tile will always stick to the bottom of the view.

Imports

In addition to any existing imports, you must include the following imports within your widgets.gui file:

<svg>
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui" />
    <!-- Additional Imports -->
    <link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/tile_list_widget.gui" />
  </defs>
</svg>

Usage

Here is an example with text

<svg>
  <use href="#tile-list">
    <use href="#tile-list-header" class="tile-list-item">
      <text>Header</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 1</text>
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 2</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 3</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 4</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 5</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 6</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 7</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 8</text>
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 9</text>
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <text>Text item 10</text>
    </use>
    <use href="#tile-list-footer" class="tile-list-item">
      <text>Footer</text>
    </use>
  </use>
</svg>
.tile-list-item {
  height: 80;
}

.tile-list-item text {
  height: 32;
  font-family: System-Regular;
  fill: "white";
}

The following example will display 10 images instead of <text> elements.

<svg>
  <use href="#tile-list">
    <use href="#tile-list-header" class="tile-list-item">
      <text>Header</text>
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/1.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/2.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/3.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/4.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/5.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/6.png" />
    </use>
    <use href="#tile-list-item" class="tile-list-item">
      <image href="img/7.png" />
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <image href="img/8.png" />
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <image href="img/9.png" />
    </use>
     <use href="#tile-list-item" class="tile-list-item">
      <image href="img/10.png" />
    </use>
    <use href="#tile-list-footer" class="tile-list-item">
      <text>Footer</text>
    </use>
  </use>
</svg>
image {
  height: 32;
  width: 32;
}

.tile-list-item {
  height: 80;
}

.tile-list-item text {
  height: 32;
  font-family: System-Regular;
  fill: "white";
}

Configuration

There are a number of settings which affect the behavior of the list.

Reorder

The reorder-enabled setting allow the user to drag and drop items to affect their sort order. The possible values are 0 for disabled, and 1 for enabled which is the default configuration.

Each child tile-list-item must have a unique ID for reordering to be automatically persisted.

<svg>
  <use href="#tile-list">
    <var id="reorder-enabled" value="0" />
    <!-- tile-list-items go here -->
  </use>
</svg>

Peek Mode

By default the list will have peek functionality enabled: clicking on a tile that is partially off the view will cause the tile to align to the edge of the view without the click interacting with elements inside the tile. The peek functionality can be specifically disabled by including the peek-enabled setting with the value 0. When peek is disabled, clicks on a partially visible tile will interact with the tile content the same way it would when the tile is fully on the view, and the view will not automatically scroll to align to the tile.

<!-- disable peek mode -->
<svg>
  <use href="#tile-list">
    <var id="peek-enabled" value="0" />
    <!-- tile-list-items go here -->
  </use>
</svg>

Alignment

The align-mode setting can take 0 for no alignment and 1 for alignment to the nearest item to the top of the view. It's disabled by default.

By default the list allows the scroll to end on any position within the list. The alignment mode can be selected explicitly by including the align-mode setting. The possible values are 1 which make selects aligning to the nearest item to the top of the view after the scroll ends and 0 which result in no alignment which is the default behavior.

<!-- enable aligning to the nearest item -->
<svg>
  <use href="#tile-list">
    <var id="align-mode" value="1" />
    <!-- tile-list-items go here -->
  </use>
</svg>

Advanced Usage

The Tile List is a incredibly powerful component. In this next example we are going to create a custom tile-list-item with a horizontal separator, and a touch (onclick) event for each item.

This example configuration could be used as an application menu interface.

Include the following SVG in your index.gui file:

<svg>
  <defs>
    <symbol id="my-tile-item" href="#tile-list-item" focusable="false"
            pointer-events="none" system-events="all">
      <text id="text" />
      <rect id="tile-divider-bottom" class="tile-divider-bottom" />
      <rect id="touch-me" pointer-events="all" x="0" y="0" width="100%"
            height="100%-2" opacity="0" />
    </symbol>
  </defs>
  <use id="my-list" href="#tile-list">
    <var id="separator-height-bottom" value="2" />
    <use href="#my-tile-item" class="tile-list-item">
      <set href="text" attributeName="text-buffer" to="Menu item 1" />
    </use>
    <use href="#my-tile-item" class="tile-list-item">
      <set href="text" attributeName="text-buffer" to="Menu item 2" />
    </use>
    <use href="#my-tile-item" class="tile-list-item">
      <set href="text" attributeName="text-buffer" to="Menu item 3" />
    </use>
    <use href="#my-tile-item" class="tile-list-item">
      <set href="text" attributeName="text-buffer" to="Menu item 4" />
    </use>
    <use href="#my-tile-item" class="tile-list-item">
      <set href="text" attributeName="text-buffer" to="Menu item 5" />
    </use>
  </use>
</svg>

Include the following CSS in your styles.css file:

.tile-list-item {
  height: 88;
}

.tile-list-item text {
  font-family: System-Regular;
  fill: "white";
}

.tile-divider-bottom {
  x: 0;
  y: 100%-2;
  width: 100%;
  height: 2;
  fill: #A0A0A0;
}

Use the following JavaScript in your index.js file to handle the onclick event for each item:

import document from "document";

let list = document.getElementById("my-list");
let items = list.getElementsByClassName("tile-list-item");

items.forEach((element, index) => {
  let touch = element.getElementById("touch-me");
  touch.onclick = (evt) => {
    console.log(`touched: ${index}`);
  }
});

You can use the value property to get and set the selected zero-based index of the tile-list in JavaScript.

import document from "document";

let list = document.getElementById("my-list");

// Get the selected index
let currentIndex = list.value;

// Set the selected index
list.value = 3; // Scroll to the 4th item

Virtual Tile List

The virtual configuration of the tile-list has the advantage of being dynamically generated. Instead of using a hard-coded list of tile-items it allocates them from a pool as they are rendered. This allows for a very large list of items to be displayed, while it's actually just cycling through a small number of items from the pool.

Let's recreate the advanced example above, but this time displaying 100 items.

To setup this configuration, we first define our tile-list-item template, the tile-list itself, we enable virtual mode to 1, and define a tile-list-pool. Our pool must contain enough items to fill the screen, with a few extra to help with smooth scrolling.

The tile-list-item must be hidden (display="none") by default.

<svg>
  <defs>
    <symbol id="my-tile-item" href="#tile-list-item" focusable="false"
            pointer-events="none" system-events="all" display="none">
      <text id="text" />
      <rect id="tile-divider-bottom" class="tile-divider-bottom" />
      <rect id="touch-me" pointer-events="all" x="0" y="0" width="100%"
            height="100%-2" opacity="0" />
    </symbol>
  </defs>
  <use id="my-list" href="#tile-list">
    <var id="virtual" value="1" />
    <var id="separator-height-bottom" value="2" />

    <use id="my-pool" href="#tile-list-pool">
      <use id="my-pool[0]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[1]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[2]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[3]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[4]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[5]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[6]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[7]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[8]" href="#my-tile-item" class="tile-list-item" />
      <use id="my-pool[9]" href="#my-tile-item" class="tile-list-item" />
    </use>
  </use>
</svg>

Use the following JavaScript in your index.js file to dynamically create 100 items, and handle the onclick event for each item.

The delegate is responsible for rendering each tile-list-item as it's required. It contains 2 functions:

  • getTileInfo() - Gets the content of each tile by its index.
  • configureTile() - Configures a tile-list-item before it is displayed.
import document from "document";

let VTList = document.getElementById("my-list");

let NUM_ELEMS = 100;

VTList.delegate = {
  getTileInfo: function(index) {
    return {
      type: "my-pool",
      value: "Menu item",
      index: index
    };
  },
  configureTile: function(tile, info) {
    if (info.type == "my-pool") {
      tile.getElementById("text").text = `${info.value} ${info.index}`;
      let touch = tile.getElementById("touch-me");
      touch.onclick = evt => {
        console.log(`touched: ${info.index}`);
      };
    }
  }
};

// VTList.length must be set AFTER VTList.delegate
VTList.length = NUM_ELEMS;

Warning: Do not use the VirtualTileListItem methods .align, .show, or .hide within the configureTile() function, it will cause your application to crash.

Checkbox Tile

This example of the tile-list generates a scrollable list of checkbox items.

In addition to any existing tile-list imports above, you must include the following import within your widgets.gui file:

<link rel="import" href="/mnt/sysassets/widgets/checkbox_tile_widget.gui" />

Next, include the following SVG in your index.gui file. By setting value="1" on the checkbox-tile the item will be checked by default.

<svg>
  <use id="tile-list" href="#tile-list">
    <var id="reorder-enabled" value="0"/>
    <use href="#tile-list-item" class="tile-item">
      <use id="item0" href="#checkbox-tile">
        <set href="header/text" attributeName="text-buffer" to="Checkbox Item" />
      </use>
    </use>
    <use href="#tile-list-item" class="tile-item">
      <use id="item1" href="#checkbox-tile" value="1">
        <set href="header/text" attributeName="text-buffer" to="Selected Item" />
      </use>
    </use>
     <use href="#tile-list-item" class="tile-item">
      <use id="item2" href="#checkbox-tile">
        <set href="header/text" attributeName="text-buffer" to="Another Item" />
      </use>
    </use>
  </use>
</svg>

To add the horizontal separator, we need to add some CSS in styles.css.

.tile-divider-bottom { x: 0; y: 100%-2; width: 100%; height: 2; fill: fb-extra-dark-gray; }

Use the following JavaScript in your index.js file to handle the onclick event for each item, and track its checked state:

import document from "document";

let tileList = document.getElementById("tile-list");
let tileItems = tileList.getElementsByClassName("tile-item");

let tileState = {}

tileItems.forEach((element, index) => {
  tileState[index] = element.firstChild.value; // initial state
  element.firstChild.onclick = (evt) => {
    tileState[index] = !tileState[index];
    console.log(`item ${index} :: ${tileState[index] ? "checked" : "unchecked"}`)
  };
});

Tumbler View

The tumblerview component allows elements to be scrolled upwards or downwards vertically, like a combination lock tumbler. The scrolling is cyclical, never ending in either direction, with the system automatically picking the next available item from the list.

First you need to declare a tumblerview element as a container. By default it will have a height and width of 100%.

Then you must declare one or more tumbler-item elements, which should contain a text element.

Imports

In addition to any existing imports, you must include the following imports within your widgets.gui file:

<svg>
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui" />
    <!-- Additional Imports -->
    <link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
    <link rel="import" href="/mnt/sysassets/widgets/tumblerview_widget.gui" />
  </defs>
</svg>

Usage

The following example will display a single number tumbler.

Include the following SVG in your index.gui file:

<svg viewport-fill="fb-cyan">
  <use id="tumbler" href="#tumblerview">
    <use id="item0" href="#tumbler-item" class="item">
      <text id="content">01</text>
    </use>
    <use id="item1" href="#tumbler-item" class="item">
      <text id="content">02</text>
    </use>
    <use id="item2" href="#tumbler-item" class="item">
      <text id="content">03</text>
    </use>
    <use id="item3" href="#tumbler-item" class="item">
      <text id="content">04</text>
    </use>
    <use id="item4" href="#tumbler-item" class="item">
      <text id="content">05</text>
    </use>
    <use id="item5" href="#tumbler-item" class="item">
      <text id="content">06</text>
    </use>
    <use id="item6" href="#tumbler-item" class="item">
      <text id="content">07</text>
    </use>
    <use id="item7" href="#tumbler-item" class="item">
      <text id="content">08</text>
    </use>
    <use id="item8" href="#tumbler-item" class="item">
      <text id="content">09</text>
    </use>
    <use id="item9" href="#tumbler-item" class="item">
      <text id="content">10</text>
    </use>
  </use>
</svg>

Include the following CSS in your styles.css file:

#tumbler { y: 50%-55; }
.item { height: 90; }
.item text { font-size: 80; fill: white; x: 5;  }

Use the following JavaScript in your index.js file to interact with the tumbler and it's items:

import document from "document";

let tumbler = document.getElementById("tumbler");

let selectedIndex = tumbler.value;
let selectedItem = tumbler.getElementById("item" + selectedIndex);
let selectedValue = selectedItem.getElementById("content").text;

console.log(`index: ${selectedIndex} :: value: ${selectedValue}`);

selectedItem.getElementById("content").text = "New Value";