Archive for October, 2011

Using Explicit Height Items with IconItemRenderer

I came across SDK-31840 when building a Facebook app that shows status updates in a list.

By default, IconItemRenderer sizes to fit it’s contents. If you have a very long message (like a Facebook status update), the item renderer measures to fit the height required to display the full message. What this item renderer doesn’t handle quite right is when the a fixed (explicit) height is specified.

In the end, really needed 2 things. I wanted to cap the item renderer height and let the message truncate. I hit 2 problems (1) truncating and adding an ellipsis doesn’t work for multi-line text and (2) the message would overflow out of the item renderer when I specified an explicit height.

How did I fix it? I monkey patched my IconItemRenderer. I could have also just subclassed and replaced measure() and layoutContents(). I could have even just gone with an MXML version that I wrote that had pretty darn good performance using opaqueBackground and cacheAsBitmap set on the item renderer.

Anyhow, if you’re in the same boat or just curious, check out the patch attached to the bug.

Share on Facebook

Adding Rounded Corners and Other Styles to Mobile Lists

Flash Builder FXP (for SDK 4.5.1): StyledIconItemRendererDemo.fxp

Creating mobile-optimized item renderers based on LabelItemRenderer or IconItemRenderer is pretty straightforward. If all you want to change is the appearance and layout, override drawBackground() and layoutContents() respectively.

drawBackground() implements the backgroundColor of each item and separators between items. layoutContents() positions and sizes each part of the skin (labelDisplay, messageDisplay, and iconDisplay).

To achieve the rounded corner look in the screenshot above, I’ve done the following:

  1. Created a custom List skin that adds padding to the VerticalLayout
  2. Created a subclass of IconItemRenderer that adds styles for cornerRadius and a handful of border-related styles. The styles are implemented in drawBackground().
One thing to point out about the custom list skin. I’ve used padding on the layout here instead of constraints to achieve the same look. This lets me do 2 things (1) use 100% width and height on the List in my View and (2) justifies the VScrollBar to the right side of the View.
Share on Facebook

Adapting Flex Mobile Projects Based on Form Factor

A quick follow up on my last post. Here’s two video demos of the app (FormFactorStyles.fxp) showing how to write a single app that targets phones and tablets using the Flex SDK and Flash Builder 4.5.1.

The first video shows how I apply separate phone and tablet skins using the CSS technique seen here. The Application changes behavior based on the existence of each skin part (e.g. the two navigators). To adapt for ViewNavigator navigation (i.e. popView() and pushView()), views instead dispatch NavigateEvents that the application listens to and determines which ViewNavigator to act on. More details on that in a future post.

This second video shows how the application adds in form-factor specific behavior, again based on the presence of skin parts as well as the utility functions in my FormFactorUtil class. In portrait mode, the primary ViewNavigator is hidden automatically. This feature will be coming up in Flex 4.6 with the new SplitViewNavigator component. I’ve added event handlers for swipe gestures to hide and show the ViewNavigator. This video also shows the exact same project but running on an Android phone and tablet.

Keep in mind that I’ve written this single app that can runs on Android phones and tablets, Apple’s iPad, iPhone and iPod as well as the BlackBerry Playbook. For more information on mobile development with the Flex SDK, go to Adobe’s Flex Developer Center.

Share on Facebook

Using CSS for Phone and Tablet UI

In the brief time I spent pitching in on the MAX Companion app this year I learned a neat trick from the Adobe XD team. As you can see from the screenshots above, the launcher view looks mostly similar, but the layout and button skinning is noticeably different. This is an example of adapting an application based on the form-factor. One thing that isn’t obvious right away is that the MAX Companion is a single binary that adapts to phone and tablet form factors at runtime.

One way to do this is to use MXML states. You might have went to Glenn’s MAX session or read the posts from evangelists Michaël Chaize or Andrew Trice. All 3 talk about how to determine form factor based on resolution, then define states and state groups.

Watch: Best Practices for Building Flex Tablet Applications Glenn Ruehle
Read: Adaptive UI: Phone vs. Tablet Michaël Chaize
Read: Flex for Mobile – Device Form Factor Detection Andrew Trice

With the MXML states strategy, you could accomplish the same result by setting skin classes separately for skin and tablet states.

What I learned from the MAX Companion app was that this can also be done in CSS. Remember that Flex 4.5 introduces media queries that let you define styles (and of course skin classes) based on os-platform and application-dpi. However, CSS media queries won’t tell you anything about screen resolution. Therefore, with CSS, there’s no out-of-the box way to detect a phone vs. a tablet. Basically, what the XD team’s solution boiled down to was CSS code that looks like this:

s|Application views|LauncherView s|Button { skinClass: ClassReference("PhoneButtonSkin"); }
s|Application.tablet views|LauncherView s|Button {skinClass: ClassReference("TabletButtonSkin"); }

 

The first rule sets a default Button skin. The second rule sets a skin only when the Application has the “tablet” style name. In the MAX Companion app, on initialize, they compute the form factor based on the screen (Capabilities.screenResolutionX and Capabilities.screenResolutionY) and the DPI (Capabilities.screenDPI). Based on that information, they find the diagonal size of the screen and set application.styleName = “tablet”. It’s a super simple technique that gives you a lot more flexibility with skinning.

I personally find this approach easier to manage than the MXML states approach, especially when the skinning and layout between form factors are different enough that they become hard to manage in a single MXML file. Also, with the MXML technique, each View would require their own state declarations. With this CSS technique, the form factor detection can be centralized at the Application’s styleName.

I’ve attached FormFactorStyles.fxp as a demo of this CSS trick. In my Application’s initialize event handler, I call a utility method FormFactorUtil.initStyleName(this). This function determines the screen’s diagonal size. Anything less than 7 inches gets the “phone” style name, all others get “tablet”. The app also shows some other useful debug information like OS, screenDPI, and the difference between stage dimensions vs. screenResolutionX and screenResolutionY.

The snippet below shows how FormFactorUtil computes the screen diagonal and other debug info.

/**
 *  Updates all screen measurements when the stage is resized.
 */
private function updateSize(event:Event=null):void
{
    var stage:Stage = FlexGlobals.topLevelApplication.stage;

    _diagonal = Math.sqrt(Math.pow(Capabilities.screenResolutionX, 2) + Math.pow(Capabilities.screenResolutionY, 2));
    _diagonal = _diagonal / Capabilities.screenDPI;

    _width = Capabilities.screenResolutionX / Capabilities.screenDPI;
    _height = Capabilities.screenResolutionY / Capabilities.screenDPI;

    _formFactor = (_diagonal <= 7) ? PHONE : TABLET;

    _stageFullScreenResolution = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight);
    _stageResolution = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
    _screenResolution = new Rectangle(0, 0, Capabilities.screenResolutionX, Capabilities.screenResolutionY);
    _screenSize = new Rectangle(0, 0, _width, _height);

    instance.debugData = new ArrayCollection([
        {label: "OS", value: FormFactorUtil.os},
        {label: "screenDPI", value: Capabilities.screenDPI},
        {label: "applicationDPI", value: FlexGlobals.topLevelApplication.applicationDPI},
        {label: "stageResolution (stageWidth, stageHeight)", value: _stageResolution},
        {label: "stageFullScreenResolution (fullScreenWidth, fullScreenHeight)", value: _stageFullScreenResolution},
        {label: "screenResolution (screenResolutionX, screenResolutionY) in pixels", value: _screenResolution},
        {label: "screenSize (screenResoltionX, screenResolutionY) in inches", value: _screenSize},
        {label: "diagonal in inches", value: diagonal.toFixed(1)}
    ]);
}

 

There’s a lot more in this app to talk about. Way too much for one blog post. Check out the screen shots below and stay tuned for more tips developing phone and tablet apps simultaneously as the Flex 4.6 release date gets closer.

Share on Facebook

MAX 2011: Creating Skins and Packaging into Themes with Flex

As promised, here are the files you need to complete my lab at home. The FXP files will work for Flash Builder 4.5 or higher.

Creating Skins and Packaging into Themes with Flex – Lab workbook
Flash Builder projects (FXP) and solution files

 

 

Share on Facebook