Creating a unique ListView layout using cell-spanning in HTML

Creating a unique ListView layout using cell-spanning in HTML

  • Comments 5
  • Likes

The ListView control makes it easy for you to organize content in a beautiful and meaningful way. The ListView control takes advantage of the Windows 8 grid system, a design tool that provides a structure for variation and maintaining user interest.

Visual Studio’s Grid App Project Template showcases a simple usage of an HTML ListView that’s databound to hierarchical data.

A simple HTML ListView that's bound to hierarchical data

Figure 1: VS "Grid App" Project Template

Our Sports and Entertainment inspiration samples takes the framework from the VS template to the next level by building on top of it and simply changing content size, spacing and content positioning. In this post, I’ll show you how easy it is to do so!

Sports sample builds on top of the VS tempate and changes content size, spacing, and positioningEntertainment sample builds on top of the VS tempate and changes content size, spacing, and positioning

Different is beautiful

Just because our design tool is called the “Grid System” doesn’t mean your layout needs to be identical squares. The Windows 8 grid system lets you use size, space and position to set expectations for your users.

With the Windows 8 grid system, you can size, space, and position to set expectations for users

You can see this in action in the Windows Store.

  • Larger content draws users’ attention, allowing you to emphasize certain content.
  • Larger white space between content indicates a break in continuity, enabling users to understand relationships and grouping.
  • For left-to-right locales, the furthest left is the “beginning” of an app, so users understand the order in which they should consume your content and its relative importance. (Similarly, for right-to-left locales, the furthest right is the “beginning” of an app.)

Layouts that uses a variety of size and space are perceived as more crafted and professional. Users enjoy and have more confidence using apps that are polished. This is why we built the ListView control to make it easy for you to leverage size, space and positioning to create meaningful and engaging layouts.

In this post, we will focus on how to create content with different sizes with the ListView by using cell spanning in JavaScript and HTML.

Cell spanning

The ListView control supports “cell spanning”, which allows your content to span across more than one row or column. It’s similar in concept to a table, where the smallest unit in the grid is called a cell, and every item must be some multiple of cells wide and high.

To leverage cell spanning, you first need to provide a groupInfo function to the CellSpanningLayout.

(Note: CellSpanningLayout is available in WinJS 2.0 for Windows 8.1. Similar capabilities are available in WinJS 1.0 and Windows 8 through the GridLayout. For details, refer to scenario 4 of the HTML ListView item templates sample that can be found in the Windows 8 app samples pack.)

JavaScript:

// groupInfo function
function myGroupInfo () {
return {
enableCellSpanning: true, // enables cell spanning
cellWidth: 100, // cell width in pixels
cellHeight: 100 // cell height in pixels
};
}

HTML:

<div data-win-control="WinJS.UI.ListView" data-win-options="{ 
...
layout: {type: WinJS.UI.CellSpanningLayout, groupInfo: myGroupInfo } }"
>
</div>

The groupInfo function should return an object with three properties set that determine how cell spanning should operate:

  • enableCellSpanning – enables the cell spanning when set to true.
  • cellWidth – establishes the width of a single cell, measured in pixels. You should set this to be the smallest width of any item you’re planning to put into your list.
  • cellHeight – establishes the height of a single cell, measured in pixels. You should set this to be the smallest height of any item you’re planning to put into your list.

Once the groupInfo function has been provided, you can create items of different sizes by modifying your itemTemplate so that it returns each item according to the size you want that item to have. Conceptually, items are multiples of the cell width and height, but in practice there’s a bit more to it due to the margins between items.

Consider the example above where you have defined a 100x100 pixel cell size. You’d imagine your cellSize (either cellHeight or cellWidth) as the size of the smallest item that will show up in your cell spanning list.  All other items in the list should be some multiple of the cellSize—meaning if your cellSize is 100x100, then you can have items 100x200, or 200x100, or 200x200, or 400x400, but never 400x450.

In actuality, the size of each item in your cell spanning list isn’t an exact pixel-multiple of the cell size, since each item has margins and those need to be taken into account.  To determine the correct sizes for content that will contain two or three cells stacked on top of each other, we need to include margins into the calculation.

To better illustrate this, let’s take the example above where the smallest unit is 100x100 pixels, and you want 5 pixels of padding around your cell, but no border or margin.

Step 1: Calculate cell size

Before we start, let’s take a look at what happens when you have two 100x100 pixels cells stacked on top of each other:

An image showing what happens when you have two cells stacked on each other

As you can see, we need to take into account the win-container bottom margin from Cell1 and the top margin from Cell2. This means, when you stack two 100x100 px cell on top of each other, you actually get more than 200px! So, we need to find out what the margin values are. We can do so by looking in default.css where this is defined:

.win-horizontal .win-gridlayout .win-container {
margin: 5px;
}
.win-vertical .win-gridlayout .win-container {
margin: 5px 24px 5px 7px;
}
.win-rtl > .win-vertical .win-gridlayout .win-container {
margin: 5px 7px 5px 24px;
}

From the default values, we can see that for a ListView using horizontal grid layout, the top & bottom margin is 5px.

So plugging that value in, we get our calculation for 2*cellHeight:

2 * 100px + 5px (bottom margin) + 5px (top margin)

= 200px + 10px

= 210px

Now, to calculate 3* cellHeight— remember, there’s one more set of margins to keep track of:

3 * 100px + 2 * (5px (bottom margin) + 5px (top margin))

= 300px + 2 * (10px)

= 300px + 20px

= 320px

Given the two calculations below, we can turn the calculation into an equation:

Let x be the number of cells, cellWidth be the width of a single cell, and cellHeight be the height of a single cell:

total cell width = x * cellWidth + (x - 1) * (win-container left margin + win-container right margin)

total cell height = x * cellHeight + (x - 1) * (win-container top margin + win-container bottom margin)

 

Calculating each cell height:

Table showing cell height calculations

 

Calculating each cell width:

Table showing calculations of cell width

Step 2: Calculate itemTemplate size

Now that we know how big each cell is, we need to determine the itemTemplate’s height. As previously mentioned, we want an item padding of 5px around the content (i.e. top, bottom, left and right), no border, and no margin.

itemtemplatesize

Calculating itemTemplate’s height:

Table showing itemTemplates height

 

Calculating itemTemplate’s width:

Table showing itemTemplate's width

Step 3: Plug this into code

Now that we have our values, all we need to do is plug this into our CSS, HTML and JavaScript!

First we put the itemTemplate height, width, padding, and border properties into the CSS.

CSS:

/* Small size */ 
.small
{
width: 90px;
height: 90px;
border: 0px;
padding: 5px;
overflow: hidden;
background-color: Pink;
}
/* Medium size */
.medium
{
width: 90px;
height: 200px;
padding: 5px;
border: 0px;
overflow: hidden;
background-color: LightGreen;
}
/* Large size */
.large
{
width: 90px;
height: 310px;
padding: 5px;
border: 0px;
overflow: hidden;
background-color: LightBlue;
}

We use the total cell height in our JavaScript code:

// Cell spanning data that has a type property that can be used to select an item size
var myCellSpanningData = new WinJS.Binding.List([
{ text: "...", type: "small" },
{ text: "...", type: "medium" },
{ text: "...", type: "large" }
]);

// Total size of item excluding the exterior margin
var sizeMap = {
// Item height: 90
// Item padding: 10
// Item border: 0
// Total height: 100
small: { width: 100, height: 100 },
// Item height of 2 items: 180
// Item padding of 2 items: 20
// Item border of 2 items: 0
// Margin between items: 10
// Total height: 210
medium: { width: 100, height: 210 },
// Item height of 3 items: 270
// Item padding of 3 items: 30
// Item border of 3 items: 0
// Margin between items: 20
// Total height: 320
large: { width: 100, height: 320 },
// Default to small size
defaultSize: { width: 100, height: 100 }
};

// Item info function that returns the size of a cell spanning item
function myItemInfo(itemIndex) {
var size = sizeMap.defaultSize;

// Get the item from the Binding.List
var item = myCellSpanningData.getAt(itemIndex);
if (item) {
// Get the size based on the item type
size = sizeMap[item.type];
}

return size;
});

Tip: In itemInfo functions above, you might noticed that instead of mapping out each individual data item, we added an attribute to each data item to represent the size of the item. Then using that attribute we return the item’s size. This is a great way to reduce the size of the map!

Finally, make sure you provide the myItemInfo function to the layout in your ListView:

HTML:

<div data-win-control="WinJS.UI.ListView" data-win-options="{ 
...
layout: {type: WinJS.UI.CellSpanningLayout,
groupInfo: myGroupInfo,
itemInfo: myItemInfo } }"
>
</div>

Results:

results

Remember that conceptually, the width and height of each item needs to be a multiple of the width and height of the cell; for example, if a cell is 1x wide and 1x high, then you can make an item 4x wide by 1x high, or 2x wide by 3x high, etc. However, you can’t have an item that is 1x wide by 2.5x high, since that’s not an even multiple.

In closing

Varying the sizes of your ListView items is easy and can help create a polished and captivating app that users will be delighted to use. In this post I’ve only covered how to create different sizes of cell, but you can also vary the amount of white space between content by updating the margins and padding.

For more information, see the following:

-Kathy Kam, Senior Program Manager, Windows (@kathykam)

A special thanks to Ryan Demopoulous, Senior Program Manager, Windows, and Paul Gildea, Program Manager II, for this post.

5 Comments
You must be logged in to comment. Sign in or Join Now
  • Is it just me or does CellSpanningLayout not work at all? I'm trying to convert my existing GridLayouts to avoid the depricated warning to no avail...

    I get theerror:

    0x800a139e - JavaScript runtime error: WinJS.UI.GridLayout.ItemInfoIsInvalid:

    Invalid argument: An itemInfo function must be provided which returns an object with numeric width and height properties.

    However, the ListView is not using GridLayout it is using CellSpanningLayout, and itemInfo does not seem to be the problem. The only thing that saves my listview from the debugger is commenting out the enableCellSpanning property in the groupInfo function, which honestly why does it even need that property if I am using a CellSpanningLayout...? What is even the point of this over GridLayout if they need the same properties?

    Or is this just not implemented yet in the Windows 8.1 RC?

  • Nathan
    63 Posts

    Lumiatic, certainly yes. Here are 456 official sample apps (and counting) build with HTML5, CSS and JavaScript: code.msdn.microsoft.com/.../search

  • Does windows 8 apps build up using HTML5? By the way Microsoft's CEO is leaving in 12 Months www.mobileosworld.com/.../microsoft-ceo-steve-ballmer-to-retire_25.html

  • Nathan
    63 Posts

    Can't agree more with akshy2000. Would you please do a similar blog post with XAML and C# in comparison with this?

    For HTML5 in Windows Store, please opt out and show how can we leverage zurb-foundation (http://foundation.zurb.com/); a successful responsive grid system. This would definitely bring value to the developers base.

    Thank you.

  • What did the authors think while writing this post?

    "Oh, hey! Let's do a post about grid with variable cell size and you know, let's keep it to HTML only. Also, let's not mention this HTML thing in title or anywhere else. Because, who uses XAML anymore, right? I mean, what the hell is XAML anyway!"