Tutorial

Learn PhoneGap Build

473880-636021952776340473_338x600_thumb

PhoneGap and its open-source sister Apache Cordova simplify cross-platform app development. You can code an app once, and then compile it to run anywhere: iOS, Android, or Windows Phone. PhoneGap Build is the cloud-based version, which allows you to take apps built with HTML, CSS, and JavaScript and compile them into native, store-ready mobile apps. All without any SDKs.

In this course, Chris Griffith introduces the PhoneGap ecosystem and the basics of PhoneGap Build. He shows how to set up an account for development and create, configure, and compile your first project with PhoneGap Build. Once you’ve mastered these fundamentals, Chris shows how to extend your app plugins, debug your app, and then prep it for release in the App Store, Google Play store, or Windows Store.

Duration: 1 hr, 24 minutes

Check it out!

Ionic 2 Full Swipe

Note: I will be updating this to RC0 shortly. I do know there is a minor issue with the button’s width not responding to the expanded space.

While working on my upcoming book on the Ionic framework from O’Reilly, I was reading over the blog post about some new additions to the <ion-item-sliding> component supporting a full swipe gesture. I hopped over to the docs to see if they explained how to enable it. Unfortunately, they did not have anything posted yet, so I began to deconstruct it from the code sample. Here is the sample:

<ion-item-sliding>
  <ion-item> Item 1 </ion-item>
  <ion-item-options side="left">
    <button>Mail</button>
  </ion-item-options>
  <ion-item-options side="right" (ionSwipe)="saveItem(item)">
    <button danger>
      Trash
    </button>  
    <button secondary expandable (click)="saveItem(item)">  
       Save
    </button>  
  </ion-item-options> 
</ion-item-sliding>

To support this interaction, two things must be added to our<ion-item-sliding>. First, we need to add the expandable directive to the button.

<button secondary expandable (click)=”saveItem(item)”>

This allows for the visual feedback of the button growing as the user swipes across the item.

swipe_demo

Typically this is attached to the item that is closest to the end of the row. To listen for the swipe gesture, we only need to include an ionSwipe event listener to the <ion-item-options> component. This listener should call the same function as if the user tapped on the item. Here is a simple Plunker showcasing it.

Learn Apache Cordova

lynda-cordova

Apache Cordova is the open-source version of PhoneGap, the leading tool for cross-platform app development. It’s a write-once, run-anywhere solution specifically designed for mobile. But to ensure a smooth cross-platform workflow, it helps to know some setup and configuration basics. In this course, Chris Griffith introduces Apache Cordova and the PhoneGap ecosystem, including the two command-line interface (CLI) tools and the PhoneGap desktop app. He shows how to set up your local system and how to create, configure, and build your first project with the Cordova CLI. Once you’ve mastered the fundamentals, Chris shows how to extend your app with native and third-party plugins that enable features such as QR code detection and geolocation, and debug your app, preview it in an emulator or on an actual device, and then prep it for release in the Apple Store or on Google Play.

Duration: 1 hr, 24 minutes

Check it out!

Centering Gallery Elements

Recently, I was rebuilding one of my websites to be responsive. It is important to take advantage of the capabilities of modern browsers and be responsive, to support the growing use of the site on mobile devices. One portion of the design was a set of image gallery pages. These pages are pretty straight-forward, up to 5 columns of photos per row centered within the width of the page. As the window width reduces, the number of columns reduces. Again, nothing out of the ordinary with this design.

figure1

Block version of the design

 

I began by centering the containing div by setting the CSS properties of margin-left and the margin-right values to “auto”. That positioned the containing div correctly and it responded as expected as the browser width was changed. However, as the width of the window reduced, the thumbnails would begin to start to flow down to the next row, but they would display centered within the containing div. Not exactly the design I was looking for.

Centered elements

Centered elements

I applied a float:left to the thumbnails, and my centering last row was fixed! However, it introduced a new problem–the thumbnails no longer appeared to be centered as a group within the page. Adding the float to the thumbnails introduced extra spacing between the last column and the right boundary of the containing div.

Highlighting the margin right issue

Highlighting the margin right issue

I knew that had to be solved, so I began looking at many of my favorite tutorial sites, and found nothing. Lots of great samples of gallery pages, but all using the full width of browser in their samples or the thumbnail sizes would adapt to their widths. Nothing seemed to fit my design.

Next, I decided to look at using Flexbox. I had made the choice to only support “modern” browsers, so I knew that I did not need to worry too much about compatibility issues. But the same issues remained as I experimented with the various flex layout options; the last row items would be centered, or the gap on the right existed. Back to the drawing board!

Then I got to thinking about how the layout was computed. Each thumbnail would take the same fixed amount of space. Each would position itself to the left due to setting the float property to left. If the thumbnail did not have enough space within the width of the container, it would move to the next row. Float 101, right? But how did it know the space it had? I only defined the containing div to have a max-width and to center itself, and the width would vary based on the width of the window. It then struck me that if the width of the containing div matched the number of allowable columns, then there would not be extra space along the right.

Eureka!

If I can set the containing div to match my column widths, that container will still be properly centered. So I calculated the computed widths for 2,3,4, and 5 columns of thumbnails. So, when the browser’s width reaches specific widths, the containing div’s width is fixed to match the allowable number of columns. With a fixed width instead of a dynamic width, it can be properly centered on the page. Design problem solved!
The resulting CSS looks like this

<style> 
 #photoMenu {
   margin-left: auto;
   margin-right: auto;
   height: auto;
   min-height: 220px;
 }
 
 .thumbnail {
   position: relative;
   border: 5px solid #ddd;
   float: left;
   margin: 20px;
   width: 160px;
 }
 
 .thumbnail img {
  max-width: 100%;
 }
 
 .thumbnail h3 {
   position: absolute;
   bottom: 0;
   left: 0;
   width: 100%;
   margin: 0;
   text-align: center;
   color: white;
   font: bold 1em/1.5em Verdana, Sans-Serif;
   background: rgb(0, 0, 0);
 }
 
 @media (min-width: 315px) {
   #photoMenu {
     background-color:darkred;
     width: 210px;
   }
 }
 
 @media (min-width: 525px) {
   #photoMenu {
     background-color: darkseagreen;
     width: 420px;
   }
 }
 
 @media (min-width: 735px) {
   #photoMenu {
     background-color: rebeccapurple;
     width: 630px;
   }
 }
 
 @media (min-width: 945px) {
   #photoMenu {
     background-color: bisque;
     width: 840px;
   }
 }
 
 @media (min-width: 1155px) {
   #photoMenu {
     background-color: aqua;
     width: 1050px;
   }
 }
 </style>

For each of the media query breakpoints, I added a background color just to highlight it. Here is what the HTML looks like:

<div id="photoMenu">
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
  <div class="thumbnail">
    <img src="thumbnail.png" alt="">
    <h3>Title</h3>
  </div>
</div>

You can see the completed sample here.

Prototyping with Bootstrap workshop at UXPA 2015

logo

I am excited to announce that I will be giving a workshop on Monday evening at the upcoming UXPA conference entitled: “Rapid HTML prototyping with Bootstrap”. Registration for the conference is not open yet, but there are only 10 slots available. I am really looking forward to leading this workshop. Hope to see you there!

Details at: http://uxpa2015.org/

Adobe MAX Lab Update: #2

This additional lab is short one, but will add event listeners in the event the device loses or gains network access. PhoneGap has event listeners for a variety of device events such as:

  • deviceready
  • pause
  • resume
  • online
  • offline
  • backbutton
  • batterycritical
  • batterylow
  • batterystatus
  • menubutton
  • searchbutton
  • startcallbutton
  • endcallbutton
  • volumedownbutton
  • volumeupbutton

We will add our event listeners within the device ready function to listen for both the change from being online to offline, as well as the reverse.

function onDeviceReady() {
   checkConnection();
   document.addEventListener("online", onOnline, false);
   document.addEventListener("offline", onOffline, false);
 }

The two functions simply toggle the network state variable based on the network state.

function onOnline(event){
   isConnected = true;
}
function onOffline(event){
   isConnected = false;
}

If while using our application, we have a network status change, the application can properly respond to it. This may not seem like much, but defensive programming techniques can improve the overall user experience of your application. We all know that the best user experience will often win in a crowded marketplace.

The project files are available on my GitHub repo.

Adobe MAX Lab: Update #1

Well, it took a little longer than I planned, but here is the first of the additional labs exercises I promised during my Adobe MAX workshop.

The lab is going to focus on checking if the app has access to a network, and handling the static Google map if the user is not online.

First we need to add is this to our config.xml file:

<feature name="http://api.phonegap.com/1.0/network"/>

This will allow our application access to the network status information.

Now, open the app.js file (which is located in the js folder). On the first line, add this:

var isConnected = true;

We are going to use this variable to hold the status of our network state.

If you are familiar with the $(document).ready that is typically used in many web apps, there is a similar api call to test if the mobile device is ready:

// Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);

Just like you have to wait for an HTML’s DOM to be ready, we also must wait for our device to be ready. Once the device is ready, it will fire  ‘deviceready‘ event, which we will then call our onDeviceReady function.

// PhoneGap is loaded and it is now safe to make calls Cordova methods
function onDeviceReady() {
    checkConnection();
}

Our onDeviceReady function currently only makes a call to the checkConnection function, but later labs will add other features.

PhoneGap API: Connection

The checkConnection function makes our first PhoneGap API call: navigator.connection.type. The Connection API allows us quickly check the network state and cellular network information. Possible values it can return are:

  • Connection.UNKNOWN
  • Connection.ETHERNET
  • Connection.WIFI
  • Connection.CELL_2G
  • Connection.CELL_3G
  • Connection.CELL_4G
  • Connection.CELL
  • Connection.NONE

Note: For iOS, the actual network type is not known (2G,3G,4G).

function checkConnection() {
   var networkState = navigator.connection.type;
   if (networkState == "none" ) {
       isConnected = false;
   }
}

So, if the application is not on a network, the isConnected variable is set to false. To test this, enable Airplane mode on your device, then run the application again.

Now that we have our initial network status, we can modify our park details template to either show a map if we are connected, or a message that we are unable to show a map.

Still in the app.js file, locate the code that generates the Park Details. It will begin with:

$('#parkDetailsPage').on('pagebeforeshow', function(event) {

Since Javascript is a dynamic language, we can easily add a new property to our park details object. In this case, we will append our connection status to the object.

currentParkData.isConnected = isConnected;

Why are we doing this? Don’t we have a globally scoped variable that has our connection status? Yes, but we are going to leverage some additional functionality in the Mustache templating engine.

Template Partials

What good is a templating system if it can’t have its own templates? That is what partials are html fragments that can be mixed into your template. When you make your call to Mustache to render your html, you pass your partial object as your third parameter. In our case it will look like this:

parkDetailsHTML = Mustache.to_html(parkDetailsTemplate, currentParkData, mapPartial);

Partials are stored as an object using a key name / template structure. Here is what our mapPartial looks like (this is located in the templates.js file):

var mapPartial = {online:'<h3>Park Location</h3><p id="parkMap"><img src="http://maps.google.com/maps/api/staticmap?center={{lat}},{{lon}}&zoom=10&markers=color:green|{{lat}},{{lon}}&size=400x400&sensor=true" width="400"></p>', offline: '<h3>Park Location</h3><p id="parkMap">Unable to display park map.</p>' };

Since it is an object, we can pass in more than one partial to Mustache. In this case, we pass in one partial for the online case, and one partial for the offline case. Now we need to modify the main portion of the template to use the partials.

To have Mustache use the partial, simply insert {{>partialname}} into the section of your template. Remember that isConnected property we added to the data set that our template is going to use? Well, Mustache also has the ability to work with conditional sections. Conditional sections only render if the condition evaluates to true. A conditional section begins with {{#condition}} and ends with {{/condition}}. “condition” can be a boolean value or a function returning a boolean.

Open the templates.js file and change the map portion of our existing template to this:

parkDetailsTemplate += '{{#isConnected}}{{>online}}{{/isConnected}}{{^isConnected}}{{>offline}}{{/isConnected}}';

What this snippet is saying is if the user is connected ({{#isConnected}}), then insert the online partial ({{>online}}). If the user is not connected ({{^isConnected}}) then insert the offline partial ({{>offline}}). The {{/isConnected}} tag tells Mustache that this is the end of the conditional check.

With these few changes, our app can now test the connection status and easily adjust its templated output.

You can download the completed files from my GitHub repo.

The next lab will look at using the GPS sensors and calculating distance to each park.

D2WC jQueryMobile Training

Thanks again to everyone who came to my training session at this year’s D2WC! I hope everyone was able to learn a bit more about both jQueryMobile and PhoneGap. As promised here are all the slides and demo files that I used during the training:

Flash Catalyst: Gallery & Datalists

When working with Flash Catalyst, often you will use the Datalist for displaying content. What is not always clear is how you can interact with each item in the Datalist. Let’s start with a simple Datalist of five photos.

The user can click on a photo, and view a larger version of the photo and some other information. But how to do this?

Gallery Details Sample

With the Datalist selected, go to the Interactions panel, and add an On Select interaction:

Interactions Panel

Now the additional setting that will make all this work, is the last option, “When a specific item is selected”. You will have to add an interaction for EACH item in your Datalist (this is where knowing ActionScript would play off, as you could write a simple event handler for this). Starting with 0 for the first item (programmers love to start counting from zero), keep adding interactions, and adjusting the item value.

Now you might encounter the 20 state limit of Flash Catalyst, so some up front planning might be needed to wrap the content within a custom component to work around that issue. (Again, if you were programming this design, you would have a template UI that is automatically populated via code).

On the state that displays our larger photo, I have included a Close button to return the user to the initial gallery screen. But there is a slight issue that the item we clicked on in the Datalist is still showing in a selected state. This is not the best user experience. To unselect the Datalist, we need to add an Action Sequence.

Again, with the Datalist selected on the Gallery screen, go to the Interactions panel, and Add Interaction – On Select. Now change the action to Play Action Sequence. Leave the last option to”When any item is selected”.

Now, select the Timelines Panel in the lower left. You should see an item under the Action Sequences panel. Select this item. The timeline will show an empty Action Sequence. There is a button along the button that says “+ Add Action”. Click this menu, then choose “Set Property”.

Available Actions

This will bring up the Properties Panel:

Properties Panel

Set the property to “Selected index” and the value to -1. Flash Catalyst uses -1 to mean that nothing is selected. Now when the user clicks on a photo, the selection state is forgotten.

Here is what a interactions panel will look like for a Datalist with 3 items clickable. Note that the Play Action Sequence is the last item in the list. If you place it before the Play Transition actions, it will not work.

Sample Interactions Panel

Here is a quick sample FXP that you can look at and play with.

Titanium Week Series

For those interested in learning more about using Titanium’s Appcelerator as a mobile development solution, they are running a series of webcasts next week that might be of interest. I have been using this as my iOS solution for sometime and have really enjoyed it. Here are some of the topics:

Welcome to Titanium! | Monday, January 9th

What’s New in Titanium 1.8 | Tuesday, January 10th

Best Practices in Mobile Development | Wednesday, January 11th

Targeting the Barnes and Noble NOOK with Titanium Mobile | Thursday, January 12th

Full-Stack Enterprise Mobile Application Development | Friday, January 13th

To register or learn more visit: http://developer.appcelerator.com/blog/2012/01/titanium-week-starts-today.html