Windows 8 Metro style simple music app example

It was a long weekend here in the UK and it rained a little and so I had a bit of spare time to put together a make-it-up-as-you-go-along screencasts around a simplistic Windows 8 metro style app that lets me play music from albums found in my music library.

I chose to do this in HTML and JavaScript.

As always, I’m not suggesting this is “perfect” or “correct” but I thought it might be useful and along the way it touches on some topics like;

  • using a query against the local storage to get a view of the music collection
  • using a ListView to present both list and grid views of the data
  • playing music with an HTML5 audio tag
  • using Visual Studio and Expression Blend to write the code/set up the basics of the UI
  • allowing music to continue in the background and handling the controls to make sure the user can still pause/play etc. on that music
  • making sure that the app tries to do the right thing to respond to sound level changes such that when another music app comes along, it pauses its playing
  • making sure that the app tries to do the right thing to respond to suspend/resume/terminate on Windows 8 so that it saves state to try and remember what music it was playing.

This ended up as 6 separate screencast videos that I’ve linked to below in order – I’m not sure whether Vimeo is the best means for this or not as my strong recommendation would be to download the videos and then play them at 1.6 to 1.8 times their original speed as it makes my voice less boring Smile

Part 1 (click the Vimeo icon to download the video)

http://vimeo.com/moogaloop.swf?clip_id=40036382&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0

Part 2 (click the Vimeo icon to download the video)

Part 3 (click the Vimeo icon to download the video)

Part 4 (click the Vimeo icon to download the video)

Part 5 (click the Vimeo icon to download the video)

Part 6 (click the Vimeo icon to download the video)

Enjoy. I have some more of these (with a little more structure to them perhaps Smile) which I’m hoping to push to Channel 9 at some point in the coming weeks or, alternatively, I’ll drop them out here if that doesn’t work out.

CSS3 Transitions and Animations

Animations in the XAML based world

I first really came to animations as part of UI (other than the odd animated GIF that we used to use to display file copy progress and so on) with the arrival into my world of WPF and then Silverlight.

In that world, you have the notion of a Storyboard which contains a bunch of animations. I once drew this diagram of it;

image

and so an animation transitions a property from some start value to some end value over some period of time using some easing function (including linear) and with some repeat behaviour. A Storyboard is then just a collection of those than be treated as a unit with, optionally, its own timings and repeat behaviour and so on.

The storyboard or the animations within it target a particular object and a particular property on that object that is to be animated.

These Storyboards can be coded against in order to start/stop them and to add event handlers in order to know when they start/stop and so on.

They can also be built into more complex, declarative groupings and be driven from triggers although the support for that is much richer in WPF than it is in Silverlight. You can “trigger” such that when the mouse is over element A then storyboard B should be run and so on.

This became the basis of state transitions as represented by the Visual State Manager in Silverlight (and latterly WPF) which codified the idea that a “piece” of UI typically has N states and a clever way of moving from one to another would be to define that transition as a set of Storyboards that need to be run to move states.

What that picture suggests is that you can animate double, color and point values but what it doesn’t say is that not every property in the whole system can be animated but, rather, there are specific properties ( dependency properties ) on particular elements that open themselves up to animation. Most relevant properties supported animation so that rarely proved problematic.

Animations in the CSS(3) based world

More recently, I’ve been looking at how CSS handles animations (and transitions) and there’s a couple of great articles from colleagues of mine that walk through this really well so I thought I’d highlight them here;

Introduction to CSS Transitions (David Catuhe)

Introduction to CSS Animations (David Rousset)

What I find “comforting” is that the very same principles from the XAML world are there (not surprisingly given that animations are animations whatever technology you’re dealing with);

  • animate from property value on some element from some start point to some end point
  • animate over a period of time
  • apply an easing function or just be linear
  • provide some initial delay
  • handle some events to know when things start/stop
  • particular types of properties can be animated (number, color, etc)
  • particular properties on particular elements can be animated

and so it’s different but feels very familiar – I’d definitely recommend taking a look at the articles that David and David have written up as they do a great job of explaining things to the newcomer.

Zooming & Panning with CSS in IE 10

Something that I’ve been experimenting with just a little lately in the IE10 Preview (available on the Windows Developer Preview) is the idea of how simple HTML content (e.g. a DIV or an IMG) can respond to touch events in order to support the sort of gesture based interactions that a user might expect to use on a touch-first device – specifically here for zooming and panning.

Where touch isn’t the primary input mechanism, the same interactions can be driven by mouse/keyboard.

In the past, I'd have expected to write code to provide the sort of functionality that IE10 supports via some (currently vendor specific) CSS attributes. These make it easy to enable scenarios that are common and simple to use but aren’t necessarily simple to implement.

Zooming

Let’s say that I’ve got a really simple piece of “UI” represented by this block of HTML;

<html style="height:100%">

<head>
	<style type="text/css">
		body
		{
			height: 100%;
			-ms-content-zooming:none;
		}
		#grid
		{
			display: -ms-grid;
			-ms-grid-columns: 1fr 8fr 1fr;
			-ms-grid-rows: 1fr 8fr 1fr;
			height:100%;
		}
		#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: none;
		}
		#image
		{
			width: 100%;
			height: 100%;
		}
		#text
		{
			-ms-grid-row:3;
			-ms-grid-column:2;
			-ms-grid-row-alignment:stretch;
			-ms-grid-column-alignment:stretch;
			background-color: #FF0000;
		}
	</style>

</head>

<body>


   <div id="grid">
        <div id="container">
            <img id="image" src="img0.jpg" style="width: 100%; height: 100%" />
        </div>
	<div id="text">this is just some text to check for zoooming</div>
  	 </div>

	</div>
</body>
</html>

which displays;

image

With just this HTML in IE10, if I use my touch screen and try and do something like a pinch gesture on the content then the browser does nothing. For example, if I do a "shrink" pinch then nothing happens. Note that this is because I've set the -ms-content-zooming on my body element to none – otherwise the browser would have scaled the whole content and I wanted to start from a clean slate here with no zooming anywhere.

That HTML has a DIV that contains an IMG and if I want to do something "active" in response to a zoom gesture on that DIV then I could say so via my CSS;

	#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: scroll;
			-ms-content-zooming:zoom;
		}

changing the overflow there and adding the -ms-content-zooming attribute set to zoom allows my IMG containing DIV to be zoomed via a pinch/zoom gesture ( or equivalent mouse/keyboard shortcut ).

However, I can only zoom in, enlarging the image and adding scrollbars;

image

that's purely because I haven't set up the limits that I want for zooming. If I was to specify the maximum and minimum sizes for zooming;

#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: scroll;
			-ms-content-zooming:zoom;
			-ms-content-zoom-boundary-max: 500%;
			-ms-content-zoom-boundary-min: 75%;
		}

then I can now zoom the DIV down (or out) with a pinch gesture down to 3/4 of its original size and in (or up) to 5 times as large;

image

and all of that comes for free in the browser. Where might I use it? You can think of scenarios where you might have content that you want to be able to display at a default size and yet offer the capability to zoom in and see a little more detail ( maybe a tube map or something along those lines? ) – it's nice functionality to have to hand for zero effort Smile

At the moment, my zooming is unguided in that I can zoom to 75, 76, 77% or wherever I happen to release the pinch gesture. Often, touch interactions are a little tricky to be accurate about and so you can provide "guide points" or “snap points” for the zooming to guide the gesture.

There's 2 ways of specifying these "snap points" – as snapIntervals or as a snapList. Quick examples below;

 

  • snapInterval(25%, 25%) means that we want to guide the user to be able to scale the DIV to 25%, 50%, 75%, 100% and so on up to the 500% max that we've specified as the boundary.
  • snapList(25%, 100%, 200%, 300%, 400%, 500%) is a more explicit list of the points that we are interested in guiding the user’s pinch/zoom gestures to.

and either way I set those up using something like;

	#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: scroll;
			-ms-content-zooming:zoom;
			-ms-content-zoom-boundary-max: 500%;
			-ms-content-zoom-boundary-min: 25%;
			-ms-content-zoom-snap-type: mandatory;
			-ms-content-zoom-snap-points: snapList(75%, 150%, 200%, 300%, 400%, 500%);
		}

and then the browser is going to take my expand gesture and guide it towards one of those values that I've specified as a snap point.

I also have a choice as to how I want those snap-points to be handled.

I can choose to go with mandatory snap points which the previous CSS uses then that means that when the zoom/pinch gesture completes it will always be adjusted from its end point to the nearest snap point.

If I choose to go with proximity for –ms-content-zoom-snap-type instead then the zoom/pinch gesture will only be adjusted to the nearest snap point if it happens to land near to one of those snap points in the first place.

It’s not quite as easy to see the effect of these snap points on zooming as it is on panning unless you choose them somewhat artificially just to make it obvious. With panning though it’s far more obvious…

Panning ( or scrolling )

Rather than zooming, let's say that I want to control the ability to scroll/pan. If I change my HTML to provide a "2 x 2" viewport onto content which is actually a 6 x 4 grid as below;

<html style="height:100%">

<head>
	<style type="text/css">
		body
		{
			height: 100%;
			-ms-content-zooming:none;
		}
		#grid
		{
			display: -ms-grid;
			-ms-grid-columns: 1fr 8fr 1fr;
			-ms-grid-rows: 1fr 8fr 1fr;
			height:100%;
		}
		#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: auto;
		}
		#content
		{
			width: 300%;
			height: 200%;
			display: -ms-grid;
			-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
			-ms-grid-rows: 1fr 1fr 1fr 1fr;
		}

	</style>

</head>

<body>
	<div id="grid">
		<div id="container">
            		<div id="content">
				<div style="-ms-grid-column:1;-ms-grid-row:1;background-color:red"></div>
				<div style="-ms-grid-column:2;-ms-grid-row:1;background-color:green"></div>
				<div style="-ms-grid-column:1;-ms-grid-row:2;background-color:yellow"></div>
				<div style="-ms-grid-column:2;-ms-grid-row:2;background-color:blue"></div>
				<div style="-ms-grid-column:3;-ms-grid-row:1;background-color:orange"></div>
				<div style="-ms-grid-column:4;-ms-grid-row:1;background-color:pink"></div>
				<div style="-ms-grid-column:3;-ms-grid-row:2;background-color:black"></div>
				<div style="-ms-grid-column:4;-ms-grid-row:2;background-color:silver"></div>
				<div style="-ms-grid-column:5;-ms-grid-row:1;background-color:red"></div>
				<div style="-ms-grid-column:6;-ms-grid-row:1;background-color:green"></div>
				<div style="-ms-grid-column:5;-ms-grid-row:2;background-color:yellow"></div>
				<div style="-ms-grid-column:6;-ms-grid-row:2;background-color:blue"></div>
				<div style="-ms-grid-column:1;-ms-grid-row:3;background-color:orange"></div>
				<div style="-ms-grid-column:2;-ms-grid-row:3;background-color:pink"></div>
				<div style="-ms-grid-column:1;-ms-grid-row:4;background-color:black"></div>
				<div style="-ms-grid-column:2;-ms-grid-row:4;background-color:silver"></div>
				<div style="-ms-grid-column:3;-ms-grid-row:3;background-color:red"></div>
				<div style="-ms-grid-column:4;-ms-grid-row:3;background-color:green"></div>
				<div style="-ms-grid-column:3;-ms-grid-row:4;background-color:yellow"></div>
				<div style="-ms-grid-column:4;-ms-grid-row:4;background-color:blue"></div>
				<div style="-ms-grid-column:5;-ms-grid-row:3;background-color:orange"></div>
				<div style="-ms-grid-column:6;-ms-grid-row:3;background-color:pink"></div>
				<div style="-ms-grid-column:5;-ms-grid-row:4;background-color:black"></div>
				<div style="-ms-grid-column:6;-ms-grid-row:4;background-color:silver"></div>
			</div>
        	</div>
	</div>
</body>
</html>

then I immediately get an area that is 3 times wider and twice as high as the DIV which is providing a “viewport” onto the content and so scrollbars appear (because of my auto setting);

image

Rather than drag around on the scrollbars (which aren’t very touch friendly), I can just pan around on the content itself to move it along on the X and Y axes;

image

If I wanted to limit the scrolling then I can use -ms-scroll-boundary ( left, right, top, bottom ) so with this additional CSS;

	#container
		{
			-ms-scroll-boundary-left: 0px;
			-ms-scroll-boundary-right: 200%;

I can now only scroll my grid to the right by "2 squares" or 100% of the width of the grid container itself so as far as to see;

image

what that picture was trying to show is that there is content off to the right here but I can't pan to it because of the -ms-scroll-boundary-right setting.

That's all great but, once again, from the point of a touch user if this content was actually meaningful rather than just a bunch of coloured squares I might want to provide some guides for the user's scrolling. I can do that by changing my CSS in a similar way to providing guides for zooming;

		#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: auto;
			-ms-scroll-snap-x: mandatory snapInterval(0%, 50%);
		}

and then the scrolling will snap me (in a mandatory manner here) to each of my grid squares as I pan to the right/left;

image

image

I should say that the text there was drawn with a mouse rather than a pen or a finger Smile and I can also do this vertically;

		#container
		{
			-ms-grid-column: 2;
			-ms-grid-row: 2;
			overflow: auto;
			-ms-scroll-snap-x: mandatory snapInterval(0%, 50%);
			-ms-scroll-snap-y: mandatory snapInterval(0%, 50%);
		}

and now I'm snapping in 2 directions of panning;

image

Going back to my content when not constrained by snap points – i.e. with my #container DIV styled by;

#container
{
	-ms-grid-column: 2;
	-ms-grid-row: 2;
	overflow: auto;
}

then the content will largely just pan around in any direction and in any amount by following my finger as I pan around. If I want to again provide a bit more guidance around the panning and constrain it to largely be either horizontal or vertical then I can add “rails”;

#container
{
	-ms-grid-column: 2;
	-ms-grid-row: 2;
	overflow: auto;
	-ms-scroll-rails: railed;
}

then the user gets a more “guided” experience for their pan gesture in that if a pan along a particular axis is detected then slight movements along the other axis will be ignored so that the pan is “guided” horizontally or vertically.

I only came across these capabilities the other day (when someone pointed them out to me) and it was a minor revelation that the browser could handle these kinds of gestures for me with minimal effort – the doc page is available if you want to look in some more detail or see the other attributes that I left out here.