Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Example for VirtualTileList

I want to implement a really long list and found VirtualTileList but I can't figure out how to implement it.

Someone has a simple example how to use it? Thanks!

 

https://dev.fitbit.com/build/reference/device-api/document/#interface-virtualtilelist

Best Answer
0 Votes
12 REPLIES 12

Hi Gollygosh,

 

here you go!

 

GUI:

 

<svg>
  <symbol id='colour-item' href='#tile-list-item' class="tile-item" height='50' display='none' focusable="false" pointer-events="none" system-events="all">
<g id='transform'> <!-- here you can animate your tile-->
<rect id='bg' height='100%' width='100%' />
<text id='title-text' fill='white' y='35' x='5' text-length="20"></text>
<rect id='tile-divider-bottom' class='list-separator' />
</g>
</symbol>

<symbol id='separate-item' href='#tile-list-item' height='5' display='none'>
<rect id='bg' height='100%' width='100%' fill='black' />
<rect id='tile-divider-bottom' class='list-separator' />
</symbol>


<use id="my-list" href="#tile-list" y="0" x="0" width="100%" height="100%">
<var id="separator-height-bottom" value="2" />
<var id='virtual' value='1' />
<var id="reorder-enabled" value="1" />
<var id="peek-enabled" value="1" />

<use id='colour-pool' href='#tile-list-pool'>
<use id='colour-pool[1]' href='#colour-item' />
<use id='colour-pool[2]' href='#colour-item' />
<use id='colour-pool[3]' href='#colour-item' />
<use id='colour-pool[4]' href='#colour-item' />
<use id='colour-pool[5]' href='#colour-item' />
<use id='colour-pool[6]' href='#colour-item' />
<use id='colour-pool[7]' href='#colour-item' />
<use id='colour-pool[8]' href='#colour-item' />
<use id='colour-pool[9]' href='#colour-item' />
<use id='colour-pool[10]' href='#colour-item' />
<use id='colour-pool[11]' href='#colour-item' />
<use id='colour-pool[12]' href='#colour-item' />
<use id='colour-pool[13]' href='#colour-item' />
</use>
</use>
</svg>

 

 

Javascript&colon;

 

 

var NUM_ELEMS = 100;
    
    this.list.delegate = {
     getTileInfo : function(index) {
let tile_tile = "lorem ipsum";
let tile_type = "my-type"; return { type : tile_type, title: tile_title, color : '#FF0000', //or which color you prefere index : index }; }, configureTile : function(tile, info) { tile.getElementById('bg').style.fill = info.color; tile.getElementById('title-text').text = info.title; tile.info = info;

tile.onclick = (evt) => {
// do what ever you want
tile.align({alignment: 'top', animate: true, redraw: true });
} } }; // KNOWN ISSUE: It is currently required that VTList.length be set AFTER VTList.delegate this.list.length = NUM_ELEMS;

 

Best Answer
0 Votes
Best Answer
0 Votes

Regardless whether I'm using this example, the original example or my own implementation I always get "Error 0 Critical glue error" in the console and a black screen on the simulator. Whenever I scroll (on the black screen) I get a bunch of new glue errors. Anybody has a clue?

Best Answer
0 Votes
Best Answer
0 Votes

I can get it working now. I do get a strange bug (perhaps in my own code) where on one launch the virtual list will work fine, while on another launch of the app it will be limited to the number of tiles predefined in the SVG. Restarting the app most often fixes the issue. Perhaps some kind of race condition?

Best Answer
0 Votes

Would need to see what you're doing in code. Can you put it on github?

Best Answer
0 Votes

I am getting this at the moment. My virtual tile list will only display the number of tiles predefined in the pool in the .gui and frequently/normally refuses to show index 0 also. The length variable is showing as the actual size I want it to be (15) if I console.log this at runtime, but the app refuses to draw tiles 0 and 9-14 when my .gui has 8 pool indexes predefined.

 

I have tried this on the simulator and my Ionic, and have tried uninstalling the app and rebuilding, but always the same.

 

I'm using the code from Virtual Tile List on https://dev.fitbit.com/build/guides/user-interface/svg-components/views/ but I have changed some of the variable names to fit my own. I am also using the Ionic Views framework, but no idea if this matters...

 

@JonFitbit The sample .zip linked-to above also seems to be broken now. All I get is:

image.png

 

 My .gui

<svg id="PickExerciseGUI" display="none">

  <defs>
    <symbol id="tile" 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="list" href="#tile-list">
    <var id="reorder-enabled" value="0" />
    <var id="peek-enabled" value="1" />
    <var id="separator-height-bottom" value="2" />
    <var id="virtual" value="1" />
    
    <use id="pool" href="#tile-list-pool">
      <use id="pool[0]" href="#tile" class="tile-list-item" />
      <use id="pool[1]" href="#tile" class="tile-list-item" />
      <use id="pool[2]" href="#tile" class="tile-list-item" />
      <use id="pool[3]" href="#tile" class="tile-list-item" />
      <use id="pool[4]" href="#tile" class="tile-list-item" />
      <use id="pool[5]" href="#tile" class="tile-list-item" />
      <use id="pool[6]" href="#tile" class="tile-list-item" />
      <use id="pool[7]" href="#tile" class="tile-list-item" />
    </use>
    
  </use>
  
</svg>

My .js

import document from "document";
import { View, $at, Application } from './view'
import { log } from './log';
import { exercisesList } from './savedata'

const $ = $at( '#PickExerciseGUI' );

export class PickExercise extends View
{
  el = $();
  list = $('#list');
    
  onMount()
  {
    
    this.list.delegate = {
      
      getTileInfo: function(index)
      {
        log("Getting info for tile " + index);
        return { type: "pool", value: exercisesList.exercise[index].name, index: index };
      },
      
      configureTile: function(tile, info)
      {
        log("Configuring tile " + info.index + ": " + info.value);
        
        if (info.type == "pool")
        {  
          tile.getElementById("text").text = info.value;
          let touch = tile.getElementById("touch-me");
          touch.onclick = evt => { log("Selected Exercise: " + info.value); };
        }
      }
      
    };

    // list.length must be set AFTER list.delegate
    this.list.length = exercisesList.exercise.length;
    log("pickExercise list length = " + this.list.length);
    
    this.onKeyUp   = () => { console.log("PickExercise: Up "); }
    this.onKeyDown = () => { console.log("PickExercise: Down"); }
    this.onKeyBack = () => { console.log( "PickExercise -> BuildWorkout"); Application.switchTo('BuildWorkout'); }
  }

  onRender(){}

  onUnmount(){}
}

My .css

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

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

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

Best Answer
0 Votes

Actually, I now suspect that it might be the Ionic Views framework which is breaking this... Finally have a working test project, and the only real difference I can see is that in this project I don't have to mark the svg in index.gui as display="none", as I don't need to stop it rendering.

 

Will see if it's possible to change this within the Ionic Views system tomorrow...

 

 

 

Best Answer
0 Votes

No, it wasn't that - it's that your pool seems to need to be a minimum of 10 tiles (i.e., 0-9 are all declared in your .gui file) before the system works properly... Simply adding two more slots into my pool has fixed the list in my main app and so now all 15 exercises show each time.

 

Will see if the pool size needs to grow further as I add more exercises into my text file.

Best Answer
0 Votes

I have just hacked a toy app which uses a VirtualTile list ... in a complex way.

 

There are 2 templates for each list item...and there is also a marquee in the mix 🙂

 

You can see the code at https://github.com/adiroiban/fitbit-os-assistant-relay

 

App ScreenshotApp Screenshot

Best Answer
0 Votes

Reopening this after, what, two years!  🙂

 

I have my virtual tile list implemented and basic functionality is there.  I tried adding:

      <var id="reorder-enabled" value="1"/>

to the invocation in index.gui (not really expecting it to work) and it doesn't work, of course.

 

I guess I could attach my own mouse down and mouse up routines, but it's not clear how I could use this to reorder the list.  Is there an example of reordering somewhere?

 

Best Answer
0 Votes

Ok, I'll quickly mention here that it is entirely possible to attach routines to the onmouseup and onmousedown events of a tile, inside the configureTile() function.  Using this, you can then save away the time when the mouse tile was touched, check it against when the tile was un-touched, and if that difference is more than, e.g., 1 second, you can scoot down all fo the tiles (in our list) and move this one to the top.

Having done that, you can then generate a refresh of the display by simply setting the VTList.length to something other than what it is.  (I simply have it cycle between two values.)

You can also scroll the list to a particular item by setting VTList.value (Thanks "Sergio") to the item number which you want centered.  (Of course, if you're moving the item to the top, then the autoscroll isn't needed so much.)

Best Answer
0 Votes