Meet the Green Goblin, part 3

December 15th, 2010

Last Friday we announced a significant update to the Android Market client. A whole slew of features went into this update (and many more are to come), and this week the pixel geek in me will be talking about the new visual design of the application. Today it’s time to dive into the mechanics behind the swooshy header. The new green header is used in all Market client screens, creating visual continuity throughout the various browsing and purchasing flows. It has a whole bunch of different gradients and highlight streaks, but there’s one important thing to notice – the visuals are the same no matter the size of the header or the orientation of the device. Here is the new header in home screen under portrait mode:

And here is the header of the same screen under landscape mode:

Note how the long diagonal highlight streak that starts around the top-left corner and goes towards the bottom-right corner always intersects the curved edge – bottom in portrait and right in landscape. Let’s see the header in the portrait category listing page:

There are a couple of things worth noticing. First, the visual design maintains the connection to the main browsing pages by adding a curved bottom edge to the tab strip. Second, note how the main header visuals are maintained here without being vertically squished. The long diagonal highlight streak still intersects the curved edge, but much closer to the left edge, and you don’t even see the double converging highlights that run in the bottom part of the taller header. And here is the same header for search results (also used in my apps and all the purchase pages):

With even less height, squishing the full visuals would look very bad; instead, we only show some of the highlight streaks.

And now the fun part – how is this implemented? It’s highly recommended to always consider using nine-patch images as your first choice. It allows you to separate the visual styling from the application functionality, skin controls of different sizes in a consistent manner and take advantage of hardware acceleration (when available) since the vast majority of the system controls are styled using nine-patches. Is this what we’re currently using for the new Market client? No. Let’s see why.

Nine-patches are great if you have visual areas that are “stretchable”. Take a look at the images in the official documentation:

Nine-patch is just a 3*3 grid. The four corners are not scaled at all and are well-suited for rounded corners and varying drop-shadows. The top and bottom pieces are stretched horizontally, while the left and right pieces are scaled vertically. Finally, the center piece is scaled along both axes. This means that if you place any non-linear gradient or path in one of the non-corner areas, it will be stretched. Looking back at the target visuals of the new green header, you can see that there is nothing that can be stretched without ruining the visual appearance. While you can stretch most of the gradients, what about the highlight streaks? Scaling them up or down would result in blurry or pixelated paths. What about the curved edges? As mentioned in the first installment, the actual arc curvature depends on the pixel size of the screen, and scaling a curved anti-aliased path would result, once again, in either blurry or pixelated visuals. Less ass than what we had before, but ass nonetheless.

So instead, we’re drawing the new header visuals in code. There are no images, just a whole bunch of trigonometry, geometry and a few selected Canvas calls. The next screenshot shows a rough analysis of the swooshy header

Here we identify a number of different areas, each one with its own contour and gradient, and a number of highlight streaks, each with its own path, thickness and gradient. I could probably write another 3-4 blog entries documenting all the pixel-level details of the implementation; join the team to see the code. Just a few points worth mentioning:

  • Never ever ever allocate new objects in your custom layout or draw methods, especially if you’re doing any type of animation. Allocating lots of small objects makes garbage collector sad and your animations jerky.
  • Call setWillNotDraw(false) in the constructor of your custom view group that implements the onDraw(Canvas). Otherwise your custom drawing will not be called. If your custom view does not extend the ViewGroup, no need to call this method.
  • Canvas.clipPath(Path) is your friend for any non-trivial custom painting code. Surround it with Canvas.save() and Canvas.restore() so that you don’t need to worry about subsequent graphic calls on the Canvas object. But make absolute sure that they match – if you call Canvas.restore() one too many times, it will affect the visual appearance in most unpredictable ways. You can also use a more reliable Canvas.restoreToCount() – thanks to Romain for the tip.
  • If your clip path contains diagonal lines or arcs and you then call Canvas.drawPath when the paint style is FILL, you will end up with aliased edge (diagonal or curved). Instead, you will need to compute the clipped path yourself (brush up on your trig). Don’t forget to call Paint.setAntiAlias(true). This may be less noticeable on higher-density screens such as Droid X or Nexus S, but is extremely visible on lower end hardware such as G1 or Flipout.
  • Drop shadows that follow custom paths are tricky. Our design calls for a translucent drop shadow that follows the curved arc. After trying a number of options, with Paint.setShadowLayer and RadialGradient among them, the most performant one turned out to be drawing a series of arcs. The arcs start from the thickest stroke with the lowest alpha and progress towards the thinnest stroke with the highest alpha. There is no best option that fits all requirements. It depends on the specific visuals that you’re looking for and how heavy the performance aspect of each specific implementation is.
  • Gradients that use translucent or transparent colors should use the RGB values that match the background color (more info here).
  • Don’t use direct pixel values. Multiply all such values by the Context.getResources().getDisplayMetrics().density.
  • Don’t use hard coded colors. Extract them to res/colors.xml and load them once with Resources.getColor().
  • Math is your friend. Don’t be afraid of it.
  • Never ever ever allocate new objects in your custom layout or draw methods, especially if you’re doing any type of animation. Allocating lots of small objects makes garbage collector sad and your animations jerky.


That’s it for today. Tomorrow i’ll talk about various random bits and pieces.

Meet the Green Goblin, part 2

December 14th, 2010

Last Friday we announced a significant update to the Android Market client. A whole slew of features went into this update (and many more are to come), and this week the pixel geek in me will be talking about the new visual design of the application. After talking about custom layouts and overlapping non-rectangular components, it’s time to talk about organizing visual information on landscape orientation. It is rather unfortunate that the vast majority of application designers and developers do not spend time optimizing the user experience for wide screens and just port the “default” portrait layout. Let’s take a look at the old home screen of the Market client:

I’ll spare my actual thoughts on this screen, but it looks like ass. From top down:

  • Way too much vertical space for the header. The icon is unnecessarily large, the font looks a little dated and the search button just hangs in mid-air.
  • The Apps / Games / Downloads look like tabs, but are not actually tabs. Tapping one of these moves to a different screen that shows the relevant content.
  • The three-pane promo widget takes almost half the screen height and is a usability disaster. Not only the user cannot swipe to the previous / next triplet. The worst thing is that tapping on the specific thumbnail does not take you to the details of the app. Instead, it takes you to the category of the app, and then you need to “hunt down” the matching row.
  • With all this vertical space taken, the actual list of featured apps is not even visible – besides the header, that is.

And here how the landing page of the new Market client looks like in landscape mode:

Here, we’re putting the user in control. The screen has now two sections – the carousel + extra controls and the list of featured apps:

  • The main title bar (with the search button) does not extend the full screen width and leaves enough vertical space to show full four rows of featured apps.
  • The carousel allows swiping to both sides so that you can go to the previous app even after auto-advance animation kicks in and advances the carousel.
  • We have enough vertical space below the carousel to show the title, price and rating of the fronted app – leaving enough white space to separate the carousel from the navigation buttons below.
  • The navigation buttons now look like actual buttons. They support traversal with D-pad / trackball and show correct highlight outlines on focus and press.
  • The list of featured apps spans the full screen height and shows full four rows on the “common” hardware configuration (Nexus-type screen size / density). I personally thing that making each row more narrow is a usability improvement as the price / rating is closer to the app title / developer name.

Next, let’s look at the top-level category listing in the old client:

This one is a tad more usable, with two full rows of categories visible. Of course, the fat title bar is still there, and the promo switcher takes the whole screen width and has a whole bunch of unbalanced white space around it. In addition, there’s a whole lot of white space to the right of each category row. Let’s see how this screen looks in the new client:

Preserving the overall layout of the home screen, the promoted apps are now displayed in a carousel. The user is no longer at the mercy of promo switcher – swiping is fully supported, and if auto-advance animation is too fast, you can always swipe back (and we actually increase the auto-advance interval once the user starts interacting with the carousel). We also have enough vertical space to show not only the promo description, but also the title, rating and price for the fronted app. And since the category list spans the full screen height, we can fit full five rows, and a much taller scroll window.

Next up – the app listing of the specific category. Here is the old client in all its glory:

Tabs are actually tabs for a change, but all the rest is still ass. Let’s see how this screen looks in the new client:

As on the previous screen, the promoted apps are in an interactive carousel. The tabs are now much lighter and don’t command too much visual attention. Personally i also like that the tab texts are closer and don’t have too much space between them. And we have enough vertical space to show full four list rows, with a much taller scroll window.

Finally, let’s see the app details page in the old client:

What can i say? Fat title, fat tabs and fat button bar take so much vertical space that the actual content has less than half the screen height to view and scroll. This screen is by far the worst usability offender as far as the content perusal goes. Let’s see how this screen looks in the new client:

Preserving the same top-level organization, the top-level information on the app is displayed to the left – along with the action buttons to install, buy, update or uninstall the app. The rest of the information is displayed to the right, providing the full screen height for comfortable skimming and scrolling. There’s definitely room for improving the visual arrangement and balance of the app info in the left side – remember that we’re not done yet :)

Android devices come in all shapes and sizes, and we strongly encourage the application developers and designers to invest extra effort in addressing usability aspects of landscape orientation. This does not mean that you should fill every single white area with yet another control. But you shouldn’t be blindly forcing the portrait-optimized layout either. And of course, don’t forget the “small” details such as different screen sizes, resolutions or localization. Here is just a small example from the new Market client:

This is running under Korean which has rather long translations for “top paid”, “top free” and “just in”. At runtime, we dynamically find the largest font size that can fit at most two lines of text in the specific tab button. All buttons have exactly the same width and the layout enforces the middle button to be aligned with the horizontal center of the tab strip. Finally, the tab strip itself has custom left padding that pushes it “away” from the curved arc, while the light gray background extends all the way below the arc. You know, pushing pixels :)

That’s it for today’s installment. Tomorrow i’m going to talk about custom drawing and the green swooshes on the new title bars and carousels.

Design, uninterrupted #111

December 9th, 2010

Today’s post highlights the design of BottlerocketCreative.com. An attractive single-page design features a strong balance around the center vertical axis, clean typography with a number of embedded fonts and noise textures that help break the monotonicity of large dark header and footer sections. Light sepia is used throughout the main section for background, decorative elements and text styling.

Note how the desaturated red from the main logo is used sparingly for the two contact links and the follow-me-on-Twitter link in the footer. Also note the simple yet effective drop-shadow rollover effects on the portfolio thumbnails and the off-by-one translucent text shadow around the text sections to improve readability.

Food for thought

December 9th, 2010

Engineers who insist on doing everything themselves underestimate the talent and skill needed to succeed in other domains, and thus also shortchange their own ideas and ambitions. Designers who refuse to interface with the technical side of things, both in using and harnessing some amount of technical knowledge to understand the limits and possibilities of product, or in using engineers to design products (solutions) to fit needs (problems), miss out on opportunities to create the most effective products possible.

From “On designers in Silicon Valley” by Nina Khosla.