Well here we are after what seems like an age of tweaking, the Oxford Dictionaries Quick Search app is finally available for installation. It can be found on the iTunes website here, and on Google Play here. The Windows Phone 8 version should with luck be out in a few days.
As the developer of course I'm going to say it's a brilliant app, but that would verge on shameless astroturfing. What I can say is that it's a simple and lightweight free English dictionary look-up app that I hope users will find useful.
Under the hood, it's a client for the Oxford Dictionaries API. This of course means that it requires a data connection to run, but does give the advantage of the app taking very little space and providing the most comprehensive and up-to-date dictionary entries. Though it's hardly a novel use for the API it does demonstrate the functionality and speed of the service, as well as the ease with which the API can be developed against.
The app uses the PhoneGap cross-platform HTML5 app framework with jQuery and jQuery Mobile providing the Javascript heavy lifting and user interface respectively. These packages have allowed us to deploy the app on three platforms in quick succession with minimal investment, something we could not have done had we been required to write all three versions natively. The quirks of the different HTML5 implementations have caused us a few headaches along the way, but not significantly more than web developers are used to when dealing with different browsers.
It's been interesting to compare side-by-side the ease of development on the different mobile platforms. Android is the easiest as you'd expect, but with a Wild West of devices and OS versions out there it needs to be. We've been scouring our colleagues for odd Android versions and form factors to try our app on, yet I'm sure we've not tried them all. In particular we decided that with 25% or thereabouts of the Android market we couldn't abandon support for version 2.3, so we've had to contend with its incomplete font support and sometimes shaky HTML5 implementation.
iOS by comparison with a set number of devices should be easy to develop for but starts to become more effort due to the stringent demands of Apple. Attaching different iOS devices to our development environment can at times be a challenge, and the ballooning demand for supporting resources such as splash screens, icons and screenshots for different resolutions and OS versions sometimes feels as though it is getting out of hand. However the App Store approval process was much quicker than we expected it to be.
The Windows Phone 8 development environment shows Microsoft's typical attention to detail. The supporting resource requirements are well-thought-out, getting the app on a device is straightforward, and the free version of Visual Studio is a delight to use. However the fact it would only run on 64 bit Windows 8 seems rather strange, and Microsoft have not quite shed their reputation for quirky HTML environments. I didn't expect the problem we had with an animated GIF loading spinner, for instance.
So it's been an interesting experience. I'd recommend PhoneGap to anyone wanting quick development of multi-platform mobile apps, though it's provided a few learning experiences of its own.
Wednesday, 13 November 2013
Tuesday, 5 November 2013
Fixed jQuery Mobile footers on Windows Phone 8
Here's a solution to something which baffled me for a while: making a jQuery Mobile footer that stayed at the bottom of the screen and didn't scroll away with the content in a PhoneGap app on Windows Phone 8.
jQuery Mobile is usually pretty good at making fixed footers. The code below works fine on Android, using data-role and data-position attributes on the footer div.
<body>
<div id="container" data-role="page" data-theme="f">
<div id="header" data-role="header" data-position="fixed" data-tap-toggle="false">
Header content here
</div><!-- /header -->
<div id="content" data-role="content">
Page content here
</div><!-- /content -->
<div data-role="footer" data-position="fixed" id="footer" data-tap-toggle="false">
Footer content here
</div><!-- /footer -->
</div><!-- /page -->
</body>
Unfortunately, on Windows Phone 8 it places the footer at the base of the screen but does not allow the content to scroll underneath it. Thus your footer scrolls up the screen with the content, hiding a bit of content as it goes and looking really horrible.
You might think breaking out of jQuery Mobile by losing the data-role and data-position attributes and then applying a fixed position and a z-index to your footer would do the job. After all, it's the standard fix for some of jQuery Mobile's footer quirks on iOS. But sadly all that does on WP8 is anchor the footer to the bottom of the page rather than the bottom of the screen, resulting in a long scroll to see it. Less obviously broken, but still not what we want.
My solution then was to apply a fixed height to the content div and allow the default WP8 overflow:auto; CSS to make its content scroll out of sight beneath it. I removed the data-role and data-position attributes from the footer and used a little piece of javascript to calculate the height of the content div from the heights of the surrounding divs and set it. Not necessarily the most elegant solution, but one that should reliably work across a range of devices.
<body>
<div id="container" data-role="page" data-theme="f">
<div id="header" data-role="header" data-position="fixed" data-tap-toggle="false">
Header content here
</div><!-- /header -->
<div id="content" data-role="content">
Page content here
</div><!-- /content -->
<div data-role="footer">
Footer content here
</div><!-- /footer -->
</div><!-- /page -->
<script>
//NB the code below references jQuery, not included in this HTML for simplicity
var headerSpace = parseInt($('#header').css("height")) + parseInt($('#header').css("marginTop")) + parseInt($('#header').css("marginBottom")) + parseInt($('#header').css("paddingTop")) + parseInt($('#header').css("paddingBottom"));
var contentSpace = parseInt($('#content').css("marginTop")) + parseInt($('#content').css("marginBottom")) + parseInt($('#content').css("paddingTop")) + parseInt($('#content').css("paddingBottom"));
var footerSpace = parseInt($('#footer').css("height")) + parseInt($('#footer').css("marginTop")) + parseInt($('#footer').css("marginBottom")) +
parseInt($('#footer').css("paddingTop")) + parseInt($('#footer').css("paddingBottom");
var contentHeight = window.innerHeight-headerSpace-contentSpace-footerSpace;
$('#content').css("height", contentHeight + "px");
</script>
</body>
I hope this helps put you on the right path. There seems to be frustratingly little documentation out there on what WP8 does and does not support, and on workarounds for what seem to be common problems. With luck this fix has plugged one such hole.
jQuery Mobile is usually pretty good at making fixed footers. The code below works fine on Android, using data-role and data-position attributes on the footer div.
<body>
<div id="container" data-role="page" data-theme="f">
<div id="header" data-role="header" data-position="fixed" data-tap-toggle="false">
Header content here
</div><!-- /header -->
<div id="content" data-role="content">
Page content here
</div><!-- /content -->
<div data-role="footer" data-position="fixed" id="footer" data-tap-toggle="false">
Footer content here
</div><!-- /footer -->
</div><!-- /page -->
</body>
Unfortunately, on Windows Phone 8 it places the footer at the base of the screen but does not allow the content to scroll underneath it. Thus your footer scrolls up the screen with the content, hiding a bit of content as it goes and looking really horrible.
You might think breaking out of jQuery Mobile by losing the data-role and data-position attributes and then applying a fixed position and a z-index to your footer would do the job. After all, it's the standard fix for some of jQuery Mobile's footer quirks on iOS. But sadly all that does on WP8 is anchor the footer to the bottom of the page rather than the bottom of the screen, resulting in a long scroll to see it. Less obviously broken, but still not what we want.
My solution then was to apply a fixed height to the content div and allow the default WP8 overflow:auto; CSS to make its content scroll out of sight beneath it. I removed the data-role and data-position attributes from the footer and used a little piece of javascript to calculate the height of the content div from the heights of the surrounding divs and set it. Not necessarily the most elegant solution, but one that should reliably work across a range of devices.
<body>
<div id="container" data-role="page" data-theme="f">
<div id="header" data-role="header" data-position="fixed" data-tap-toggle="false">
Header content here
</div><!-- /header -->
<div id="content" data-role="content">
Page content here
</div><!-- /content -->
<div data-role="footer">
Footer content here
</div><!-- /footer -->
</div><!-- /page -->
<script>
//NB the code below references jQuery, not included in this HTML for simplicity
var headerSpace = parseInt($('#header').css("height")) + parseInt($('#header').css("marginTop")) + parseInt($('#header').css("marginBottom")) + parseInt($('#header').css("paddingTop")) + parseInt($('#header').css("paddingBottom"));
var contentSpace = parseInt($('#content').css("marginTop")) + parseInt($('#content').css("marginBottom")) + parseInt($('#content').css("paddingTop")) + parseInt($('#content').css("paddingBottom"));
var footerSpace = parseInt($('#footer').css("height")) + parseInt($('#footer').css("marginTop")) + parseInt($('#footer').css("marginBottom")) +
parseInt($('#footer').css("paddingTop")) + parseInt($('#footer').css("paddingBottom");
var contentHeight = window.innerHeight-headerSpace-contentSpace-footerSpace;
$('#content').css("height", contentHeight + "px");
</script>
</body>