User Interface

Ionic Split Pane – Part 2

In this post, I am going to dig a little deeper into working with the new Ionic Split Pane component. I explored it some in this post. There are three elements I want to explore: a full header design, understanding how to navigate pages, and handling resizing.

Full Header Design

Several readers asked about how you might achieve this design:

full_header

A full header Ionic Split Pane

After playing around with different variations of the component structure and encountering some navigation troubles, I settled on using a basic CSS approach to this design.

The app.html is a standard component (sorry spacing with the brackets, blame WordPress):

This should look very close the documentation from Ionic. All we need to do is update the app.scss file with two changes:

The first change removes the line that divides the two headers. This line actually runs down the entire right side of the pane. So, with the second change, we restore the line back to the default style of a solid 1-pixel line of medium gray.
We still have two headers, but by not including any visible text in the main header, we initially have the illusion of a single header.

Handling Resizing

Here is where I encountered one of my first issues. The design worked fine in desktop sizes, but when I reduced the width below its breakpoint, my pane would disappear and along with it, my title.
The component has an event listener for when a pane state change is triggered. So, I changed my < ion-split-pane > tag to include (ionChange)=”updateTitles()”.
Now, I just needed to manage what the visible state of the pane is, and the broadcast this state to my other pages, so they could replace the empty title with my pane’s title.
Here is my app.componet.ts code:

We define a menuToggleState boolean to hold our pane’s visible state. This variable is set once the platform is ready. We have hard code the breakpoint to match the split panes. If you change that value, you will need to update it here as well.

The key to this solution is using the Ionic Events module to broadcast this value upon a state change triggered by the IonChange event. When that event occurs, we check the new width, and determine of the pane is now showing or not. Then we publish our custom event throughout our Ionic app.

In each page that is shown with the main content, I adjusted a few items. First, I had the title component is bound the title variable.

When we do not want a title visible, we set this variable to hold a space, rather than an empty string. The reason for this is, without content in the node, Ionic did not properly display any header icons. We also include a button that will auto display our hamburger menu icon when the split pane is hidden, giving us access to that content.

In the component’s code, we need to add the event listener for our custom event we broadcast from the resize action. Here is the full code:

This is for the Project Mercury page, each NASA project page has the similar event subscriber included in its constructor. For this sample, I did not rework this into a custom component to properly encapsulate the code as to not need to repeat so much of it across all these pages. The basic structure of the code listens for the event from the master component and depending on the state updates the title variable.

Now when I resize the window smaller than the breakpoint, the title is updated on the main content pages. Here is what it looks like when resized:

panesmall

and the menu being displayed:

pane_sidemenu

Page Navigation

Another tricky part of working with the split pane is understanding how to navigate pages. It was this issue that forced me to abandon several other attempts at a full header design. The heart of updating the main content from the pane is to use the @ViewChild.

Within the class for the app, we define our ViewChild to come from our root NavController using @ViewChild(Nav) nav: Nav;

Now, we can properly reference it in our component, and navigate correctly. Our list of manned NASA projects will call the projectSelected function when clicked and pass along which page to navigate to:

This function tells the nav that we referenced with the @ViewChild to set it’s rootpage to the project component we stored within our array and that is passed into this function. We also use the MenuController, to automatically close the pane if it is being shown like a normal sidemenu.

Navigation within the Main Content

If you want to have navigation with the main content to a new page, the normal navigation methods work just fine. In the sample, if you click on the NASA meatball logo, it will navigate to a new page showing the NASA worm logo. Clicking the worm logo will return you to the meatball page. However, you can now see the UX issue of having the hamburger menu and the back navigation control. But, the purpose of this exploration with just to get the core functionality working, and not worry about the UX issues. That is left to you and whatever your app’s design might be.
worm
Hopefully, this brief look further into the Split Pane component is useful. The sample code can be found in my GitHub repo. If you are wondering why I picked NASA as my sample, you can visit my other blog, https://spacequest.wordpress.com/ to learn why.

Watch your focus

Many of you might know, I enjoy a fine craft brew from time to time, and living in San Diego, one of the best microbrewery towns certainly helps. To keep track of my various tastings, I use the Untappd service (here is my profile). The app follows many of the same ideas as Foursquare; instead of places you check in with a beer. They also have a badge system among other features you would expect from a social media service.

What is interesting about the app is some of it’s history. Originally, this service was only available as a web app. A fact they were quite proud of. I would usually refer to them as the example of going the web app route versus building a native application.

Recently, they made the leap into the native app realm, by wrapping their web app with PhoneGap. This makes good sense given their previous investment. But this blog post is not about this choice, but rather to talk about a UI choice.

untappd iOS home screen

Take a look at the initial screen from the iOS version of the app. What has focus?

If you said ‘Drink Up’ or the larger yellow tab with beer bottles, you would be wrong! Instead, it is the Friends tab. So many times, I go to check in with a beer and begin typing the beer’s name in the search field only to be informed that the beer can not be found in my friends. Then I remember that I need to switch tabs to log my beer.

untappd Drink Up screen

untappd Drink Up screen

Why do I make this error? Well the designers have placed more visual emphasis on the Drink Up tab than then other tabs. By adding this visual weight to the element, a casual glance of the UI would lead the user to assume that the Drink Up tab was selected and the screen’s contents were based on that selection. In addition, except for the hint text in the search field, there is no difference in the top portion (about 20%) of either screen.

Now, logging your beers is the primary task of this app, and hence the reason for the visual emphasis for the tab’s look and feel. But what fails is that this tab is not automatically selected focus. It is an easy fix, programmatically set the default state to the Drink Up tab. One could go a bit further and maybe repeat the icons that are used on the tabs next to the search field. Let’s face it, this is an app you will use with alcohol! 😉

So, as you develop your next great mobile application, take care in what you provide focus on and how this reflected in the code. Now what’s in my ‘fridge to drink…

D2WC Short Recap & Slides

Designer / Developer Workflow Conference

I am a little late in getting around to writing about the second Designer/Developer Workflow Conference (aka D2WC) in Kansas City, Mo. This is the second time I had the pleasure of speaking here. This year’s topic was on Designing Great Mobile Apps. This was an expanded version of the talk I gave at 360|Flex. I had a wonderful time presenting it, and enjoyed all the follow up conversations.

The conference was fantastic! All the sessions I attended were well done and informative. In many cases I had to make hard choices between sessions. I only hope the recordings turn out. It was great to have some wonderful chats with the attendees.

I want to thank Dee Sadler for hosting yet another great event, and look forward to next year’s (where ever it maybe).

For a deeper write up on the conference, take a moment at read Chad Udell’s post (who I also enjoyed his preso at the conference) and Mark DuBois’ as well.

Presenting: What’s New In Flash Catalyst CS5.5

I am pleased to be presenting on What’s New in Flash Catalyst CS5.5 to the Orange County Flex User Group.

Flash Catalyst CS5.5 represents an important step forward in the Flex-based designer/developer workflow. As Flex-based applications become more visually rich, more technically complex, and more prominent in the enterprise, the ability to prototype and create visually accurate applications becomes even more critical.

I will also be raffling off a copy of Flash Catalyst CS5.5! Hope to see you there.

Date: Thursday July 7,  2011
Time: 7pm
Location:
18006 Sky Park Circle
Suite 207
Irvine, CA 92614

Designing Great Mobile Apps

I had the extreme pleasure of speaking at the recent 360|Flex Denver conference. The conference was incredibly well done, John, Nicole, and their assistants did a fantastic job!

Besides working on the mobile apps for the show ( we are still trying to figure out the session survey upload issues), I presented on “Designing Great Mobile Apps” on Tuesday afternoon. I had a lot of fun giving the presentation, even with two Adobe evangelists and one Adobe product manager in attendance (and the great Dee Sadler as well)…

I hope these slides are useful, the session was recorded by the folks at ZaaLabs, so I will let you know when it is ready. Please feel free to ping with questions or comments.

Now go build something!

[Update]

If you are interested in some resources on mobile design I would also suggest they following books:

Integrating maps into your mobile application

For many mobile applications, having some form a location-based capability is a requirement. This article will show how you can add a mapping solution to your mobile app. Most of the major map providers (Google, Yahoo, MapQuest, and Microsoft) provide ActionScript solutions that you can easily incorporate into project. Unfortunately, none of the currently available are designed for touch.

Recently, I developed the attendee guide for the recent 360|Flex East conference, and needed to add a map of the conference location, along with nearby restaurants. The application was being developed using Flash Professional CS5 (with AIR for Android extension), as the Flex 4.5 mobile framework was not yet available. My first attempt was to use the existing swc from Google. I had used their APIs before, and was familiar with the setup.

It took almost no effort to integrate the latest swc and have a working Google Map in my AIR for Android application. But there were issues to deal with…

The SWC version

 

One of the first issues I encountered was the default map controls were not optimized for touch. I had a feeling that this would be the case. Also the initialization time for the component was extremely long (30 seconds or more). I decided to address the load time first, since if I couldn’t bring up the map quickly, I would need to find a different solution. Looking at the code revealed no clues as to where I might be able to streamline the initialization. One of the issues of the long load time was there was no feedback given to the user while the component performed its initialization. Once the component was added to the stage, it assumed the top most layer and you could not overlay any elements (like a loading spinner). The screen would just show a grey rectangle where the map would be. Not the best user experience.

Since there was nothing I could do while the map did it’s thing, I decided to see if adding something before the map was actually loaded might give enough feedback to the user to make the experience acceptable. I knew from my years of prototyping that this type of solution just might do the trick. So I added a standard spinner and some loading text to the frame before the map, and a simple 5-second timer. I demonstrated each version around the office, and confirmed that folks thought the map did load faster on the version with the loading screen. In Apple’s Interface Guidelines, it refers to this illusion when talking about the splash screen.

Loading Animation

So, with the loading distraction in place, I could now address the touch-ability of the default map controls. Typically there are both pan controls and zoom controls to interact with. Since users could directly pan the map by dragging, I did not need to create a touch-friendly version of that control. I did still need to address the ability to change the scale of the map.

Unfortunately, here is where I ran into an actual hardware issue. At the time I was developing the application on the Google Nexus One (one of the few devices running FroYo, a requirement for AIR for Android), but there is a known issue with Multitouch on that device. This meant that a pinch and zoom gesture would be problematic. I needed to find a different solution to allow the user to change the scale of the map.

I created touch-friendly zoom in and zoom out controls and added them to the screen once the map finally loaded. Now I had a basic functioning map in my AIR for Android application and had it running on a device.

Google Map - Completed swc version

Now I needed to add the markers for the restaurants and the conference venue to the map. Creating markers is a fairly straightforward process of converting my graphics into MovieClips, enabling them for Export for ActionScript, then adding a bit of code to properly place them on the map. I manually geocoded (Update: Thanks to Randy Troppmann for spotting I had the term reversed) the venues into their latitudes and longitudes, so I did not need to look up that static information every time the map was accessed. The next test was to see how the info-windows would function. What good is seeing the marker for a bar if you can’t see the address?

This is where I hit the proverbial brick wall. The info window would appear, but the controls were far from usable on a touch device. Despite my best efforts, I could not modify the info window enough to make the controls usable on a mobile device.

So now what?

I decided to investigate using a new feature in AIR for Android called StageWebView. A little background on StageWebView; this is a new API that allows AIR developers to embed HTML content into their mobile applications and render it using the platform’s native rendering engine.

I removed the Google Map SWC from my project and added the following code:

var webView:StageWebView = new StageWebStage();
webView.stage = this.stage;
webView.viewPort = new Rectangle(0, 100, stage.stageWidth, stage.stageHeight);
webView.loadURL(http://map.google.com);
addChild(webView);

I recompiled the project and loaded it onto my mobile device, and a touch-friendly Google Map was displayed.

The load times were acceptable (I still kept my fake pre-loader, as there was a bit of load time ). I had touch-friendly zoom controls and scrolling. With this technical proof of concept validated, I quickly wrote a custom web page to house my map and markers.

Completed HTML version

I was still unsure how the info-windows would appear. To my pleasant surprise, the info-windows were quite touch-friendly . They were not as nice as the native elements, but certainly more usable that the ones in the SWC’s.

Info Window

So, now I have a mobile friendly map solution in my AIR for Android application. Hopefully this solution will work for you when you need to add a map to your mobile application.

Sample HTML map.

Creating Lightbox Galleries with Flash Catalyst

One of the more popular uses of Flash Catalyst by designers is to create rich and engaging portfolios. However, many can quickly become frustrated as they try to convert their visual designs into the world of components. In this tutorial I will show the how to quickly build a “lightbox”-like gallery.

Here is the basic look of our final application.

and with an image being displayed

The first step is to convert each of the six thumbnails into a button. Select each thumbnail and either use the Heads Up Display (HUD) or the contextual menu to transform it into a button. We are not going to add any interactions to these buttons yet, but now is the best time to rename each of the buttons in the library. Keeping your assets well named and organized is one of the best workflow tips that a team can have. I named each button Photo_1, Photo_2, and so on. Note: You cannot have spaces in the name.

Now let’s turn our attention to the overlays. Many first time users of Flash Catalyst would take the approach of creating a new page for each full size image and then link each button to that specific page. This solution will work, but you will quickly discover that Flash Catalyst only allows a maximum of 20 pages/states. If you have a large portfolio, you quickly will hit this limitation.

The solution within Flash Catalyst is to create what is known as a “custom component”. By encapsulating a portion of project within a custom component, we can usually avoid hitting the 20-page limit. It also allows us to keep the project in a more manageable state.
We are going to apply the same idea that we would have done by placing each photo on a separate page in main application, but now we are going to do it within the context of a custom component.

On main page, let’s add a basic rectangle using Flash Catalyst’s drawing tools. This rectangle will serve as our dimming effect. Set the width and height to match the applications (800×600). Remove the rectangle’s stroke and change the fill to black. Then adjust the opacity of the mask to 50%. All of these can be set using the Property Panel.

Now let’s add the white frame that the photo will sit on. Again, use the basic rectangle tool to draw. The photos are 640×480, so make the rectangle 680×520 pixels and then center the white rectangle on the artboard. Next place the large version of the photo that matches the first photo button, and align it to the center of the artboard. The final step for this template is to add the close button in the upper right of the white frame. Select the close button graphic and convert it to a button using the HUD.

Now select just the mask, the white frame, the photo and the close button. Using either the HUD or the contextual menu, “Convert to Custom Component”.

In the library panel, rename this component to “LightboxComponent”.

Now we can add the individual photos within this component. Double click the newly created component, and then use the Duplicate State button on the Pages/States panel.

Rename the first state to “Off” and the second state to “Photo_1”. With the elements now duplicated, we can delete them from the Off state. Select the Photo_1 State. Now let’s add the interaction to the close button. Set the interaction type to On Click, and choose the Off state as the target.

With this interaction added, you can keep duplicating the photo states as needed.  Since the portfolio only has 6 images, only 5 more states are needed. Rename each of the states to match the names of the buttons, as this will make connecting the interactions so much easier in a moment.

With the all the full sized images properly inserted, we can now add the interactions to each of the thumbnails. Using the breadcrumbs, navigate to the top level of the application. Select a thumbnail, and then using the interaction’s panel, add an On Click interaction. From Choose State select the proper state within the Lightbox component. Finally, set the “When in any state” to Off. That last setting keeps the thumbnails from working while an image is being shown.

With that our basic Lightbox style portfolio is done. You can take this further by adding transitions within the custom component.

Download the fxp.