Creating the iTunes navigation header
November 13, 2009
Recently, someone asked me what the best way to create the iTunes navigation header (seen in the iTunes music store — the black shiny bar at the top) would be. Here was my response:
The navigation header’s most prominent feature is it’s multi-stop gradient. There are four colors used in the gradient as illustrated below:
But to really capture the subtleties of the navigation header we need to look closer at the top and bottom of the component, where you’ll notice an inner shadow, and an inner glow. The inner shadow and inner glow are what make the component visually interesting.
I chose to hard code the inner shadow and inner glow sizes to 3 pixels (top) and 2 pixels (bottom) rather than produce the real effects. Real inner shadows and glows aren’t straight forward to create (I talked about them here), and are computationally expensive to recompute because they aren’t currently computed on the graphics card. So I decided to hard code the inner shadow and inner glow colors to the exact colors seen in iTunes. You could figure out their grayscale and alpha values to make them reusable — I’ll leave that as an exercise for the reader.
Here’s the code:
public class ITunesNavigationHeader extends JComponent { // the hard-coded preferred height. ideally this would be derived // from the font size. private static int HEADER_HEIGHT = 25; // the background colors used in the multi-stop gradient. private static Color BACKGROUND_COLOR_1 = new Color(0x393939); private static Color BACKGROUND_COLOR_2 = new Color(0x2e2e2e); private static Color BACKGROUND_COLOR_3 = new Color(0x232323); private static Color BACKGROUND_COLOR_4 = new Color(0x282828); // the color to use for the top and bottom border. private static Color BORDER_COLOR = new Color(0x171717); // the inner shadow colors on the top of the header. private static Color TOP_SHADOW_COLOR_1 = new Color(0x292929); private static Color TOP_SHADOW_COLOR_2 = new Color(0x353535); private static Color TOP_SHADOW_COLOR_3 = new Color(0x383838); // the inner shadow colors on the bottom of the header. private static Color BOTTOM_SHADOW_COLOR_1 = new Color(0x2c2c2c); private static Color BOTTOM_SHADOW_COLOR_2 = new Color(0x363636); @Override public Dimension getPreferredSize() { return new Dimension(-1, HEADER_HEIGHT); } @Override protected void paintComponent(Graphics g) { Graphics2D graphics = (Graphics2D) g.create(); // calculate the middle of the area to paint. int midY = getHeight()/2; // paint the top half of the background with the corresponding // gradient. note that if we were using Java 6, we could use a // LinearGradientPaint with multiple stops. Paint topPaint = new GradientPaint(0, 0, BACKGROUND_COLOR_1, 0, midY, BACKGROUND_COLOR_2); graphics.setPaint(topPaint); graphics.fillRect(0, 0, getWidth(), midY); // paint the top half of the background with the corresponding // gradient. Paint bottomPaint = new GradientPaint(0, midY + 1, BACKGROUND_COLOR_3, 0, getHeight(), BACKGROUND_COLOR_4); graphics.setPaint(bottomPaint); graphics.fillRect(0, midY, getWidth(), getHeight()); // draw the top inner shadow. graphics.setColor(TOP_SHADOW_COLOR_1); graphics.drawLine(0, 1, getWidth(), 1); graphics.setColor(TOP_SHADOW_COLOR_2); graphics.drawLine(0, 2, getWidth(), 2); graphics.setColor(TOP_SHADOW_COLOR_3); graphics.drawLine(0, 3, getWidth(), 3); // draw the bottom inner shadow. graphics.setColor(BOTTOM_SHADOW_COLOR_1); graphics.drawLine(0, getHeight() - 3, getWidth(), getHeight() - 3); graphics.setColor(BOTTOM_SHADOW_COLOR_2); graphics.drawLine(0, getHeight() - 2, getWidth(), getHeight() - 2); // draw the top and bottom border. graphics.setColor(BORDER_COLOR); graphics.drawLine(0, 0, getWidth(), 0); graphics.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1); graphics.dispose(); } }
November 13, 2009 at 2:34 pm
Very nice.
Thanks for share.
November 13, 2009 at 3:54 pm
I have to say that, because of your work (MacWidgets specifically) and these blog posts, I really learned to understand the Java2D API.
Great post, great work!
November 13, 2009 at 3:57 pm
I just thought about something – there is alot more to that component than just the visuals (as you obviously know). There are the little dividers, which simply consist out of a black line and a lighter gray-like line.
Could think about writing a layout manager for it (which you sort of already have for the OS X toolbar in MacWidgets, using FormLayout – with some minor changes, or perhaps none at all it could work out nicely).
November 13, 2009 at 5:44 pm
My next post will discuss how to create the actual iTunes navigation bar, which I’ll include in Mac Widgets for Java.
November 13, 2009 at 5:44 pm
Glad my posts help!
November 15, 2009 at 8:14 pm
[…] of Ken, he also blogged about ‘creating the iTunes navigation header‘ in […]
November 16, 2009 at 3:42 am
How about implementing the breadcrumb-like navigation and the popup button things?
November 16, 2009 at 12:50 pm
Hi Tristan,
I’ll implement the press-able button in the next post.
-Ken
November 17, 2009 at 9:04 am
Hi Ken,
Thanks for your work. I’m really interested of your work on the UI with Swing.
I see that http://blog.elevenworks.com/?p=15 , maybe this topic might interest you.
Thx again.
Steph
November 17, 2009 at 10:17 am
Thanks for the link Steph! I’ll check it out.
November 19, 2009 at 9:35 pm
I wonder who inspired you for this post? :-)
November 19, 2009 at 9:37 pm
Are you stepping away from your “component” approach? Instead subclassing JComponent?
November 19, 2009 at 9:38 pm
No, I’m sticking with the component model — expediency ruled the day with this example!
December 2, 2009 at 1:39 pm
[…] these items. To actually create the iTunes navigation header component, you can adapt the code from my last post, with […]
November 28, 2011 at 9:28 am
How i can Use the UI-Class? Examples?
it shows nice :)