Posts tagged "mobile"

GlobalOptimizer NullPointerException when packaging AIR applications for iOS

In some circumstances, attempting to package an AIR application for Apple iOS platform using  ipa-ad-hoc and ipa-app-store targets can result in a NullPointerException. A workaround for this problem may be to use a debug version of your SWF in the package.

When using the Project->Export Release Build… menu item to create a package, click Next on the first screen. You will notice that it will build the release SWF as it switches from this screen to the Package Settings screen.

Before you click Finish on the Package Settings screen of the Export Release Build dialog, go to your project within Finder (or File Explorer on Windows). With the Export Release Build dialog open you will not be able to do the next step within Flash Builder and you will have to do it within Finder. Copy the ePresenter.swf file found in the bin-debug directory and replace the same file in the bin-release-temp directory with the one from the bin-debug.

Once you copied the debug version into the bin-release-temp folder, you can click Finish. When I tested this, it was able to create the IPA.

Example: customizing the SpinnerList in mobile AIR

Question:

Can a SpinnerList on Android or iOS AIR be changed so that certain items in the list have a different background? For example, in a list of states, make Alaska have a black background even when it is not selected.

Answer:

That can be done with a custom item renderer for the SpinnerList. It would extend the existing item renderer and would switch how it is rendered based on data in the data source.

As with so many things in Flex, there is more than one way to do this. This example is just a suggestion. Each project is different and this example may not be the best way for each one.

Item Renderer’s Data

Item renderers should rely solely on the data property for information on how to draw themselves. Item renderers can be reused, so when the data property changes the items renderer needs to change along with it or old information may be displayed. I suggest whatever data source is used for the SpinnerList should include a flag to indicate whether the state name needs to be pre-hilited. Giving the item renderer the logic to figure out if it needs to have a different background color based on the state name makes it so you will have to change your program whenever the list of states that need to be pre-hilited changes.

A very simple data source for the SpinnerList that does this would look like this:

var rawData : Array = [
{"value":"al","hilite":false,"name":"Alabama"},
{"value":"ak","hilite":true,"name":"Alaska"},
{"value":"az","hilite":false,"name":"Arizona"},
{"value":"ar","hilite":false,"name":"Arkansas"}
];
var myDataSource : ArrayCollection = new ArrayCollection(rawData);
 

How to Change the Color of the Item Renderer Background

The code for the default item renderer should be opened up and examined to see how it is rendered. The default item renderer for the SpinnerList can be found at:

[Flex sdk]\frameworks\projects\mobilecomponents\src\spark\components\SpinnerListItemRenderer.as

Item renderers tend not to use skins in order to keep them relatively lightweight. Instead of relying on skins, they usually contain the drawing logic. This particular skin, SpinnerListItemRenderer, draws a transparent box behind itself so it can capture click events. We can override this and draw a colored box instead.

Create a new item renderer that extends the SpinnerListItemRenderer. I created a class named BackgroundColorItemRenderer within my package com.adobe.example.spinner. In this new class override the method, drawBackground, that draws this transparent box and change it so it makes the background a color. Here is my logic: if the data property does not contain a value of hilite that is equal to true then pass the method to the ancestor class for rendering. Otherwise, give the background a color.

override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
{
    if (! data.hilite)
    {
        // if no hilite, use the existing logic to draw the background
        super.drawBackground(unscaledWidth, unscaledHeight);
    }
    else
    {
        // if data.hilite == true, draw a black background
        graphics.beginFill(0x000000, 1.0);
        graphics.lineStyle();
        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
        graphics.endFill();
    }
 }
 

In this method the color for the background is hard-coded. Create a style that sets a value for this for the component to move this value from the component to the style sheet. The name for the style property can be relatively arbitrary as long as it is not the same name as any other style for the component. I added styles, spinnerBackgroundColor and spinnerBackgroundAlpha, for the item renderer. Since, when using a black background, the text color is no longer visible, I changed it to white.

@namespace spinner "com.adobe.example.spinner.*";
spinner|BackgroundColorItemRenderer {
 spinnerBackgroundColor : #000000;
 spinnerBackgroundAlpha : 1.0;
 color : #FFFFFF;
}
 

I change the drawBackground method use the value from the style sheet:

override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
{
    if (! data.hilite)
    {
        // if no hilite, use the existing logic to draw the background
        super.drawBackground(unscaledWidth, unscaledHeight);
    }
    else
    {
        // if data.hilite == true, draw a black background
        graphics.beginFill(
                getStyle(“spinnerBackgroundColo”), 
                getStyle(“spinnerBackgroundAlpha”));
        graphics.lineStyle();
        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
        graphics.endFill();
    }
 }
 

Now, all that is left to do is to assign my data source and my item renderer to the SpinnerList:

<fx:Script>
<![CDATA[
    import mx.collections.ArrayCollection;
    import mx.events.FlexEvent;

    private static const SPINNER_DATA : Array = 
        [
            {"value":"al","hilite":false,"name":"Alabama"},
            {"value":"ak","hilite":true,"name":"Alaska"},
            {"value":"az","hilite":false,"name":"Arizona"},
            {"value":"ar","hilite":false,"name":"Arkansas"}
        ];

    [Bindable]
    public var spinnerData : ArrayCollection = new ArrayCollection(SPINNER_DATA);

 ]]>
 </fx:Script>
<s:SpinnerList 
            dataProvider="{spinnerData}" 
            labelField="name" 
            width="400" 
            itemRenderer="com.adobe.example.spinner.BackgroundColorItemRenderer" />
 

Problem with iframes on Motorola Xoom

I have seen a problem with the way the Android system handles iframes on my particular tablet, the Motorola Xoom. In the most recent versions of Android, the system browser does not pass click events to iframes that overlay plugin media. You can reproduce this by creating a Web page that has a Flash movie covering the entire page and an iframe in a layer above the Flash movie. Touch events, including taps, will not be sent to the iframe at all.

Someone was kind enough to test different versions of the system on the Xoom for me. This behavior was not in the Xoom with Android 3.0.1. It showed up in the Motorola Xoom running Android 3.1 or higher. The version of the Flash player had no effect.