Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

PhoneGap From Scratch: App Template

by
This post is part of a series called PhoneGap From Scratch.
PhoneGap From Scratch: Device APIs
PhoneGap From Scratch: Twitter & Maps

Want to learn how to use PhoneGap, but don't know where to get started? Join us as we put together "Sculder", not only a tribute to an excellent science fiction TV series, but a fully-fledged native mobile application for the believer in you!

In the last two parts we have installed Phonegap, gotten a hello world running, and then taken a look at some of the functionality that Phonegap offers us. Over the next two parts, we will build our app and take a look at some of the challenges that might arise in doing so.


Planning The Application

Before we get down to code, we are going to have to a little bit of planning. This way we know exactly what we want to app to achieve and can have a good idea of the user experience. You might achieve some great work from just hitting the code straight away (something I do all the time), but even just a little bit of planning beforehand can go a long way. Thinking through scenarios in your head will allow you to deal with problems early on.

First, we need to know what core features of the application will be, how they will be accessed, and how they will be used. The app we are going to build will have the following features:

  • Find a UFO Sighting by Location
  • Take a Sighting Photo
  • List a Twitter feed of UFO Sightings

If you'd like to do wireframes for your projects, they're always good to make sure you know what you want your application to do and also roughly what you want it to look like. If the application is going to be large and have a lot of functionality, I would do some wireframes, but in this case I think that the application is small and so we can sort out the pretty basic functionality as we build the app.

If you do want to create wireframes, there are some pretty good tools out there to help you.

Mockingbird is an online tool where you can create the wireframes in the browser. You can try it out here

Balsamiq is an Adobe Air application with a whole load of templates and elements. It has a sketchy style much like Mockingbird too. You can download it here.

Omnigraffle is a mac only application which you can get a 14-day free trial here. Omnigraffle is my personal favorite and there are plenty of templates on Graffletopia for you to use.


Designing The Application

Look and feel is an important aspect of any application. When it comes to mobile applications, it's an area that many often get wrong (mostly due to lack of understanding). I'm not a designer, and I don't pretend to be one, so if I don't have a designer at hand to do the designs, I will usually just design in the browser as I code (or on the device in this case).

If you want to make sure your app looks and feels good to use (and you aren't one) hire one! Like a developer, good designers cost money. While you might not want to fork out for something you might be able to do yourself, it's best to have someone who understands design to do this for you. Your app will be a hundred times better for doing so!

There have been some great design tutorials here on Mobiletuts+, which will give you a great understanding of what is required when diving into design for mobile.

One of the most important considerations for your design is the amount of images you use. If your design is going to require you to chop up PSD files and use lots of images - something is wrong - we want to do as much as possible with CSS and as we are building for pretty modern browsers, we can harness to power of many newer CSS3 techniques for the desired output. When you begin using lots of images, it begins to effect the performance of the application. When we have to use images, which is likely, we should build up a sprite (one image file containing all of our imagery) to save HTTP requests. It's also possible to cache images on the device or use local storage too.


Markup for Mobile

Now is the time to get into actually coding the HTML, CSS, and Javascript for our application.

We will begin with some pretty basic HTML.

<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes" />
  <title>Sculder</title>
</head>
<body>

</body>
</html>

CSS support on mobile is good, but it's not great. While a lot of common styles are supported, there are some "gotcha's" as well. One of my favourite resources for checking support is caniuse.com. While the site doesn't include every browser for mobile, it is a useful reference.

Go ahead and create a new blank stylesheet and include it in the head of your html. As you may already do with your desktop browser apps, set up some basic reset styles.


html, body{
 margin: 0;
 padding: 0; 
 border: 0;
}

body {
 font-family:Arial,  sans-serif;
 line-height:1.5;
 font-size:16px;
 background: #fff;
 padding:5px;
 color: #000;
 word-wrap: break-word;
 -webkit-text-size-adjust: none;
}

h1, h2, h3, h4, h5, h6{ font-weight: normal; }

p img { float: left; margin: 0 10px 5px 0; padding: 0; }

img { border: 0; max-width: 100%; }

Next, we are going to add some basic HTML - a header and a some tab controls.

<header>
    <h1>Sculder</h1>
</header>
 
<div id="wrapper">
    <div id="main-content">
    	
	</div>
</div>
 
<footer>
	
</footer>

First, I am going to give the background a colour and then style the header and footer. I'm going to go ahead and lay them out in a pretty average way, fixing them to the top and the bottom of the screen and using iScroll to give us the ability to overcome the lack of support for position:fixed in most devices.

/*	Main Styles */

body{
	background: #222;
}

header{
    top:0; left:0;
    height:45px;
}
 
footer {
    bottom:0; left:0;
    height:48px;
    background-color:#c27b00;
    border-top:1px solid #eee;
}
 
header, footer{
	background-color:#deb500;
    padding:0;
	position:absolute;
    z-index:2;
    font-size:20px;
    width:100%;
    text-align:center;
    color:#f3f3f3;
    font-weight:bold;
    text-shadow:0 -1px 0 rgba(0,0,0,0.5);
    line-height:45px;
}

h1{
	margin:0;
	text-transform: uppercase;
}

#wrapper {
    position:absolute;
    z-index:1;
    top:45px; bottom:48px; left:0;
    width:100%;
    overflow:auto;
}
 
#main-content {
    position:absolute;
    z-index:1;
    width:100%;
    padding:0;
}

Next, we're going to download iScroll 4 from here, and include the iscroll-lite.js file. This gives us the basic functionality that we will need. We will also make a app.js file to handle all of our JavaScript functionality. Include these files in the head of your index.html.

<link rel="stylesheet" href="css/style.css">
<script src="js/iscroll-lite.js"></script>
<script src="js/app.js"></script>

In our Javascript file we need to init iscroll.

var theScroll;
function scroll(){
	theScroll = new iScroll('wrapper');
}

document.addEventListener('DOMContentLoaded', scroll, false);

Now we are going to add our tab bar in our footer.

<ul id="tab-bar">
	<li>
		<a href="#">Map</a>
	</li>

	<li>
		<a href="#">Camera</a>
	</li>

	<li>
		<a href="#">Twitter</a>
	</li>
</ul>

We are going to style our tab bar so that each element takes up a third of the space available.

#tab-bar{
    margin:0;
    padding:0;
}

#tab-bar li {
    display: inline;
    float:left;  
    width: 33.333%;
}

#tab-bar a {
    color: #cdcdcd; 
    display: block; 
    font-weight: bold; 
    overflow: hidden;  
    position: relative; 
    text-align: center; 
    text-decoration: none;
    -webkit-touch-callout:none;
}

All of this is pretty average CSS that you might use in a webpage. The only one that might be the odd one out to you is the -webkit-touch-callout:none. This rule is to stop the default action when a user holds down a link.

Thats all we're going to be doing with the tab bar, but you may want to add icons to yours, much like most apps have. Just remember to make sure you use sprites for you images to keep the hit on performance minimal.


Paging

Now that we have the skeleton of our Application ready, we can look into paging through our app. There are a number of good ways to do this. One is to load everything up-front and then hide the pages we don't want to show at first, then on a click of a link we can use CSS to slide a new container into view. Another option is to use Ajax and make an Ajax request for a HTML file and then slide that into view. As this is a relatively small application there is no harm in loading everything up-front and using CSS for the bulk of the page handling, much like jQuery Mobile does.

First we will set up some pages inside our main container.

<div id="pages">
	<div id="map" class="current">

	</div>
	<div id="camera">

	</div>
	<div id="twitter">

	</div>
</div>

Then make sure that the links href corresponds to these.

<ul id="tab-bar">
	<li>
		<a href="#map">Map</a>
	</li>

	<li>
		<a href="#camera">Camera</a>
	</li>

	<li>
		<a href="#twitter">Twitter</a>
	</li>
</ul>

Now we will hide all the pages and just display the page with the current class.

#pages > div {
    display: none;
}

#pages > div.current {
    display: block;
}

Next, we have to dive into some JavaScript. I'm going to go ahead and use jQuery for the rest of the project (not jQuery mobile). If you like, you can jQuerify the iScroll init (or not). Make sure to drop the minified version of jQuery into your JS directory as well.

First, I am going to bind a click to the anchors in the tab-bar, as we are using jQuery 1.7 we can use the new .on() function. We will then prevent the default action of a link, store the href of the clicked link in a nextPage variable, remove the current class from the current page and finally add the class to the clicked page.


$('#tab-bar a').on('click', function(e){
	e.preventDefault();
	var nextPage = $(e.target.hash); 
	$("#pages .current").removeClass("current"); 
	nextPage.addClass("current");
});

You will now have some very basic paging as the content divs will now hide and show when the links are clicked.

This is and will work absolutely fine, but to add a little extra to the paging we are going to use some CSS and make the transition between pages a bit nicer with a basic fade in, fade out.

First we need to make sure that our pages are positioned in a way that gives us some control over their display. Add the following CSS.


#pages{
    position:relative;
}


/* Update this style */

#pages > div {
    display: none;
    position: absolute;
    top:0;left:0;
    width:100%;
}

Now we are going to use CSS animation to animate the page transition. First we start with some generic setting for the animation function and the timing.


.in, .out { 
    -webkit-animation-timing-function: ease-in-out; 
    -webkit-animation-duration: 400ms;
}

The we set the keyframes for the animation of the keyframes.


@-webkit-keyframes fade-in { 
    from { opacity: 0; } to { opacity: 1; }
}

Lastly we set the Z-index to make sure that the page we just faded in is on-top.


.fade.in { 
    -webkit-animation-name: fade-in; 
    z-index: 5;
} 

.fade.out {
    z-index: 0;
}

Now we need to add some more JavaScript to add and remove the CSS classes on click. First we need a function that will take a parameter, which will be the page to navigate to, then it will add the classes necessary to fade the new page in and bind a function to webkitAnimationEnd, this will then remove the necessary classes. The function looks like this.


function page(toPage) { 
	var toPage = $(toPage),
	fromPage = $("#pages .current");
	toPage.addClass("current fade in").one("webkitAnimationEnd", function(){
		fromPage.removeClass("current fade out");
		toPage.removeClass("fade in") 
	});
	fromPage.addClass("fade out");
}

If you have never seen the jQuery method .one() before, check out the documentation its just a way of binding and then unbinding.

If you test now on your device, you will notice that if you click the current page link, it will fade-out. We need to put in an if statement before we run our page function to make sure that we are not already on the current page - if we are we can just return out of the function.


function page(toPage) { 
	var toPage = $(toPage),
	fromPage = $("#pages .current");
	if(toPage.hasClass("current") || toPage === fromPage) { 
		return;
	};
	toPage.addClass("current fade in").one("webkitAnimationEnd", function(){
		fromPage.removeClass("current fade out");
		toPage.removeClass("fade in") 
	});
	fromPage.addClass("fade out");
}

Now you can dump some text into each page container and test out on a device.

PhoneGap From Scratch - Demo

Conclusion

We've now begun building a web application and gotten our layout and paging working. In the next part we will start building out our pages, debugging on the mobile and get our Phonegap integration started.

Advertisement