Partager via


Working with tiles and the splash screen in Hilo (Windows Store apps using JavaScript and HTML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

From: Developing an end-to-end Windows Store app using JavaScript: Hilo

Previous page | Next page

When you use tiles and the splash screen effectively, you can give your users a great first-impression of your Windows Store app app.

Download

After you download the code, see Getting started with Hilo for instructions.

You will learn

  • How we incorporated an app tile that displays the user's photos.
  • How we added the splash screen.
  • What considerations to make in your own app.

Applies to

  • Windows Runtime for Windows 8
  • Windows Library for JavaScript
  • JavaScript

Why are tiles important?

Traditional Windows desktop apps use icons. Icons help to visually connect an app or file type with its brand or use. Because an icon is a static resource, you can often wait until the end of the development cycle to incorporate it. However, tiles are different from icons. Tiles add life and personality and can create a personal connection between the app and the user. The goal of tiles is to keep your users coming back by offering a personal connection.

Tip  For Hilo, we knew early that we wanted to display the user's photos on the tile. But for other apps, it might not be apparent until later what content will keep your users coming back. We recommend that you add support for tile updates when you first create your project, even if you're not yet sure what the tile will show. When you decide later what to show on the tile, the infrastructure will already be in place. This way, you won't need to retrofit your code to support tile updates later.

 

[Top]

Choosing a tile strategy

You have a few options when you choose a tile strategy. You must provide a square tile and optionally you can provide a wide tile. If you provide a wide tile, the user can decide to display the square tile instead of the wide tile. You can also display badges and notifications on your tile.

Note  Because Hilo is a photo app, we wanted to show the user's photos on the tile. You can show images on both the square and wide tile. The wide tile enables us to show multiple images, so we decided to support both. See Choosing between a square and wide tile size for info on how to choose the right tiles for your app.

 

We settled on the following rules for the tile behavior:

  • Display a wide default tile that shows the Hilo logo before the app is ever launched.
  • Each time the app is launched or resumed, update the square and wide tiles according to these rules:
    • If the user has fewer than five pictures in the Pictures folder, display the default tile that shows the Hilo logo.
    • Otherwise, randomly choose 15 pictures from the most recent 30 and set up the notification queue to cycle among three batches of five pictures. If the user chooses the square tile, it will show only the first picture from each batch.

Read Guidelines and checklist for tiles to learn how tile features relate to the different tile styles. Although you can provide notifications to the square tile, we wanted to also enable the wide tile so that we could display multiple images.

Tip  

You can also enable secondary tiles for your app. A secondary tile enables your users to pin specific content or experiences from an app to the Start screen to provide direct access to that content or experience. For more info about secondary tiles, read Pinning secondary tiles.

 

[Top]

Designing the logo images

Our UX designer created the small, square, and wide logos according to the pixel size requirements for each. The designer suggested a theme that fitted the Hilo brand. Choosing a small logo that represents your app is important so that users can identify your app when the tile displays custom content. This is especially important when the contents of your tile change frequently—you want your users to be able to easily find and identify your app. The small Hilo logo has a transparent background, so that it looks good when it appears on top of a tile notification or other background.

The images folder contains the small, square, and wide logo images. For more info about working with image resources, see Quickstart: Using file or image resources and How to name resources using qualifiers.

30 x 30 pixels

150 x 150 pixels

310 x 150 pixels

Important  Because the small logo appears on top of a tile notification, consider the color scheme that you use for the foreground color versus the background color. For Hilo, this decision was challenging because we display users' photos and we cannot know what colors will appear. We experimented with several foreground colors and chose white because we felt it looked good when displayed over most pictures. We also considered the fact that most photos do not have white as the dominant color.

 

[Top]

Placing the logos on the default tiles

The Visual Studio manifest editor makes the process of adding the default tiles relatively easy. To learn how, read Quickstart: Creating a default tile using the Visual Studio manifest editor.

[Top]

Updating tiles

You use tile templates to update the tiles. Tile templates are an XML-based approach to specify the images and text that customize the tile. The Windows.UI.Notifications namespace provides classes to update Start screen tiles. For Hilo, we used the TileUpdateManager and TileUpdater classes to get the tile template and queue the notifications. Hilo defines the Hilo.Tiles namespace and a TileUpdater object to choose the images to show on the tile, and form the XML that is provided to Windows Runtime.

Note  Each tile template enables you to display images, text, or both. We chose TileTemplateType.TileWideImageCollection for the wide tile because it shows the greatest number of images. We also chose it because we did not need to display additional text on the tile. We also use TileSquareImage to display the first image in the user's collection when they choose to show the square tile. For the complete list of options, see TileTemplateType.

 

Tile updates occur in the app's TileUpdater.update method, which is called during app initialization in default.js.

Hilo\default.js

if (currentState.kind === activation.ActivationKind.launch) {

    if (currentState.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

        // When the app is started, we want to update its tile
        // on the start screen. Since this API is not accessible 
        // inside of Blend, we only invoke it when we are not in
        // design mode.
        if (!Windows.ApplicationModel.DesignMode.designModeEnabled) {
            var tileUpdater = new Hilo.Tiles.TileUpdater();
            tileUpdater.update();
        }

Note  We considered updating the tiles when the app suspends, instead of when the app initializes, to make the updates more frequent. However, every Windows Store app should suspend as quickly as possible. Therefore, we did not want to introduce additional overhead when the app suspends. For more info, read Optimizing your app's lifecycle.

 

The TileUpdater.update method performs the following steps to update the tile in the background:

  • Create a local folder to store a copy of the thumbnails displayed on the tile (implemented in the createTileFriendlyImages function).
  • If there are at least 30 photos in the user's collection:
    • Generate thumbnails for the 30 photos in the local app folder. (This is implemented in the createTileFriendlyImages function.)
    • Randomly select 15 of the user's 30 most recent photos. (This is implemented in the createTileUpdates function).
    • Create 3 batches of 5 photos. (This is implemented in the createTileUpdates function).
  • Create the notification and update the tile. (This is implemented in the createTileUpdates and queueTileUpdates functions).

Verify your URLs describes the ways you can reference images that appear in your tile notification. We use ms-appdata:///local/ for Hilo because we copy thumbnails to a local app folder.

Note  The number of bytes consumed by the thumbnails is small, so even if very large pictures are chosen for the tile, copying the thumbnails doesn't take much time or disk space.

 

We copy photos to a local app folder for two reasons. First, we did not want to store thumbnail versions of the images in the user's personal folder. Second, we did not want to reference the user's personal folder directly, in case the user wants to delete a picture that appears on the tile.

The following example shows the TileUpdater.update method. This code controls the process that creates the thumbnails folder, selects the images, and updates the tile. We create a chain of tasks that perform the update operations. Some of the tasks here operate in a synchronous fashion, but we use the asynchronous programming model, which is a promise chain. We do this because we also have embedded calls to Windows Runtime asynchronous functions, such as getThumbnailAsync. Windows Runtime wraps all APIs in a Promise object to support asynchronous method calls, so we use the asynchronous model. We felt this made the code more consistent and easier to read.

Hilo\Hilo\Tiles\TileUpdater.js

update: function () {
    // Bind the function to a context, so that `this` will be resolved
    // when it is invoked in the promise.
    var queueTileUpdates = this.queueTileUpdates.bind(this);

    // Build a query to get the number of images needed for the tiles.
    var queryBuilder = new Hilo.ImageQueryBuilder();
    queryBuilder.count(numberOfImagesToRetrieve);

    // What follows is a chain of promises. These outline a number of 
    // asychronous operations that are executed in order. For more 
    // information on how promises work, see the readme.txt in the 
    // root of this project.
    var whenImagesForTileRetrieved = queryBuilder.build(picturesLibrary).execute();
    whenImagesForTileRetrieved
        .then(Hilo.Tiles.createTileFriendlyImages)
        .then(this.getLocalImagePaths)
        .then(Hilo.Tiles.createTileUpdates)
        .then(queueTileUpdates);
}

For more info on the promise chain that we use here, see Async programming patterns and tips.

Note  We considered multiple options for how to choose pictures. Two alternatives we considered were to choose the most recent pictures, or enable the user to select them. We went with randomly choosing 15 of the most recent 30 to get both variety and recent pictures. We felt that having users choose the pictures would be inconvenient for them, and might not entice them to come back to the app later.

 

The first function that is called in the tile updater's promise chain, createTileFriendlyImages is exported by createTileFriendlyImages.js. With that function we set the local folder where we will copy the images. We use createFolderAsync to create a subfolder in the local folder to store the tile images, and then call the copyFilesToFolder function. In this code, we use JavaScript bind function to create partially applied functions. For more information on the use of bind and partially applied functions in Hilo, see Async programming patterns and tips.

Hilo\Hilo\Tiles\createTileFriendlyImages.js

function createTileFriendlyImages(files) {
    var localFolder = applicationData.current.localFolder;

    // We utilize the concept of [Partial Application][1], specifically
    // using the [`bind`][2] method available on functions in JavaScript.
    // `bind` allows us to take an existing function and to create a new 
    // one with arguments that been already been supplied (or rather
    // "applied") ahead of time.
    //
    // [1]: http://en.wikipedia.org/wiki/Partial_application 
    // [2]: https://msdn.microsoft.com/en-us/library/windows/apps/ff841995

    // Partially apply `copyFilesToFolder` to carry the files parameter with it,
    // allowing it to be used as a promise/callback that only needs to have
    // the `targetFolder` parameter supplied.
    var copyThumbnailsToFolder = copyFilesToFolder.bind(null, files);

    // Promise to build the thumbnails and return the list of local file paths.
    var whenFolderCreated = localFolder.createFolderAsync(thumbnailFolderName, creationCollisionOption.replaceExisting);

    return whenFolderCreated
        .then(copyThumbnailsToFolder);
}

We let the Windows Runtime handle the task of generating the actual thumbnail images. The runtime scales the thumbnail as needed to fit on the tile.

To get the thumbnail from Windows Runtime, we need to set ThumbnailMode on the FileProperties object, and then call getThumbnailAsync to retrieve the actual thumbnail images.

createTileFriendlyImages.js

thumbnailMode = Windows.Storage.FileProperties.ThumbnailMode
// . . .
var whenThumbailIsReady = fileInfo.getThumbnailAsync(thumbnailMode.singleItem);

getThumbnailAsync is called in the writeThumbnailToFile function. In writeThumbnailToFile, we use WinJS.Promise.join to make sure that target files are open and thumbnails are available. When the joined promise has completed, we construct a promise chain that calls getInputStreamAt to open a file stream, copy the files to a RandomAccessStream file stream using copyAsync, flush the output stream, and then shut everything down.

Hilo\Hilo\Tiles\createTileFriendlyImages.js

function writeThumbnailToFile(sourceFile, targetFile) {
    var whenFileIsOpen = targetFile.openAsync(fileAccessMode.readWrite);
    var whenThumbailIsReady = sourceFile.getThumbnailAsync(thumbnailMode.singleItem);
    var whenEverythingIsReady = WinJS.Promise.join({ opened: whenFileIsOpen, ready: whenThumbailIsReady });

    var inputStream,
        outputStream;

    whenEverythingIsReady.then(function (args) {
        // `args` contains the output from both `whenFileIsOpen` and `whenThumbailIsReady`.
        // We can identify them by the order they were in when we joined them.
        outputStream = args.opened;
        var thumbnail = args.ready;
        inputStream = thumbnail.getInputStreamAt(0);
        return randomAccessStream.copyAsync(inputStream, outputStream);

    }).then(function () {
        return outputStream.flushAsync();

    }).done(function () {
        inputStream.close();
        outputStream.close();
    });
}

When the TileUpdater object is created, its constructor function uses the Windows.UI.Notification.TileUpdateManager class to create a TileUpdater object. The job of the TileUpdater class is to update the content of the app's tile. Use the TileUpdater.enableNotificationQueue method to queue notifications if more than one image is available.

Hilo\Hilo\Tiles\TileUpdater.js

function TileUpdaterConstructor() {
    this.tileUpdater = tileUpdateManager.createTileUpdaterForApplication();
    this.tileUpdater.clear();
    this.tileUpdater.enableNotificationQueue(true);
},

We added the call to TileUpdater.clear to support the case where the user deleted everything in the library. This method deletes the tile images.

After the app creates the thumbnails and copies them to the right place, createTileFriendlyImages, then the update method in TileUpdater.js calls createTileUpdates to build the live tile notifications. This task includes formatting the XML for the tile templates by selecting a specific XML template for both square and wide tiles. In the running app, wide tiles are used by default because the Hilo package manifest includes an image for a wide tile. The buildTileNotification function passes the paths for the thumbnail images to populateTemplateFor.wideTile.

Hilo\Hilo\Tiles\createTileUpdates.js

function buildTileNotification(thumbnailPaths) {
    // The square tile will just display the first image used for wide tile.
    var squareTileFile = thumbnailPaths[0];

    var squareTile = populateTemplateFor.squareTile(squareTileFile);
    var wideTile = populateTemplateFor.wideTile(thumbnailPaths);

    var compositeTile = buildCompositeTile(wideTile, squareTile);
    var notification = new Windows.UI.Notifications.TileNotification(compositeTile);

    return notification;
}

The buildWideTile function formats the XML for the tile update, using tileWideImageCollection as the tile template type. This template specifies XML for five images on the tile. The template builds upon the TileWideImageCollection tile template by inserting the provided list of thumbnails into the XML content template, to produce a TileNotification object.

Hilo\Hilo\Tiles\populateTemplate.js

function buildWideTile(thumbnailFilePaths) {

    // For more information about the `TileWideImageCollection` template, see:
    // https://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx#TileWideImageCollection
    var template = templates.tileWideImageCollection;

    var xml = tileUpdateManager.getTemplateContent(template);
    var images = xml.getElementsByTagName("image");

    thumbnailFilePaths.forEach(function (thumbnailFilePath, index) {
        images[index].setAttribute("src", thumbnailFilePath);
    });

    return xml;
}

When the notifications are built, then the update method in TileUpdater.js calls queueTileUpdates to update the tile. For each notification, queueTileUpdates calls TileUpdater.update to actually update the tiles in the UI.

Hilo\Hilo\Tiles\TileUpdater.js

queueTileUpdates: function (notifications) {
    var self = this;
    notifications.forEach(function (notification) {
        self.tileUpdater.update(notification);
    });
},

The XML for a typical tile notification, which you don't normally see when developing apps, looks like this:

<tile>
  <visual>
    <binding template="TileWideImageCollection">
      <image id="1" src="ms-appdata:///local/thumbnails/thumbImage_0.jpg"/>
      <image id="2" src="ms-appdata:///local/thumbnails/thumbImage_1.jpg"/>
      <image id="3" src="ms-appdata:///local/thumbnails/thumbImage_2.jpg"/>
      <image id="4" src="ms-appdata:///local/thumbnails/thumbImage_3.jpg"/>
      <image id="5" src="ms-appdata:///local/thumbnails/thumbImage_4.jpg"/>
    </binding>
  <binding template="TileSquareImage">
      <image id="1" src="ms-appdata:///local/thumbnails/thumbImage_0.jpg"/>
    </binding>
  </visual>
</tile>

Note  The wide tile template also contains a template for the square tile. This way, both the square and wide tiles are covered by a single template.

 

If you use text with your tile, or your images are sensitive to different languages and cultures, read Globalizing tile and toast notifications to learn how to globalize your tile notifications.

Use these resources to learn more about tile templates:

[Top]

Adding the splash screen

All Windows Store apps must have a splash screen, which is a composite of a splash screen image and a background color, both of which you can customize. The splash screen is shown as your app loads. As with tiles, our designer created the splash screen image. We chose an image that resembled the default tile logos and fits the Hilo brand. It was straightforward to add the splash screen to the app. Read Quickstart: Adding a splash screen to learn how.

If your app needs more time to load, you might need to display the splash screen for a longer duration, to show real-time loading information to your users. To do this, create a page that mimics the splash screen by showing the splash screen image and any additional info. For Hilo, we considered using an extended splash screen, but because the app loads the hub page very quickly, we didn't have to add it. For more info about extending the duration of the splash screen, see How to extend the splash screen.

Use these resources to learn more about splash screens:

[Top]