Monday, February 20, 2012

Creating a Flex AIR Annotator app: Part 1

Today we will start making a new program called KirAnnotator.

KirAnnotator - a light software used for adding annotations, arrows, comments to a picture, imported by the user.

This kind of program can be used for many needs - whether it is a web developer, trying to point out flaws in a site design by highlighting specific spots in the screenshot, or just a casual user drawing attention to a point of interest on a site screenshot, on a map, or any other picture.

Just like all of my Flex AIR programs, I'm making this one in FlashDevelop.

Open FD, create new Flex 4 AIR Project. I set my project's name as KirAnnotator.

In Main.mxml file, let's set up our basic layout.

Create a VGroup containing an HBox and a Canvas. The Canvas contains a Box (with 100% dimensions), which basically acts as a background for the contnet. Set the canvas' scroll policies to "on", and the inside box's vertical and horizontal aligns to middle and center.

<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#ccccdd" width="100%" height="68">

</mx:HBox>
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="on" verticalScrollPolicy="on">
<mx:Box backgroundColor="#eeeeee" width="100%" height="100%" verticalAlign="middle" horizontalAlign="center" horizontalScrollPolicy="off" verticalScrollPolicy="off">

</mx:Box>
</mx:Canvas>
</s:VGroup>

Inside the last box, add another box with an id of drawArea. Set its dimensions to 300 and 200. This is where the image will be located, as well as anything that the user draws. For now it's just a white rectangle.

Let's add some text to it, which will appear on program's launch - it should tell the user to import a picture.

Now, in the first HBox in the VGroup, add 2 IconButton objects. Those are our custom components, which I will get to soon:

<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#ccccdd" width="100%" height="68">
<custom:IconButton icon="@Embed('../lib/bubble.png')" toolTip="Annotation" enabled="true" />
<custom:IconButton icon="@Embed('../lib/bubble.png')" toolTip="Annotation" enabled="false" />
</mx:HBox>
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="on" verticalScrollPolicy="on">
<mx:Box backgroundColor="#eeeeee" width="100%" height="100%" verticalAlign="middle" horizontalAlign="center" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:Box id="drawArea" backgroundColor="#ffffff" width="300" height="200">
<s:VGroup width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
<s:Label fontSize="24" color="#444444">Welcome to KirAnnotator.</s:Label>
<s:Label fontSize="24" color="#444444">Start by</s:Label>
<s:Label fontSize="24" color="#6666ff">importing a picture!</s:Label>
</s:VGroup>
</mx:Box>
</mx:Box>
</mx:Canvas>
</s:VGroup>

You can see that I set the icon properties of the wto placeholder icon buttons to bubble.png picture located in the lib folder of the project. The picture is taken from a free icon set found on the internet:



Put it in the lib folder, name it bubble.png.

Now, because IconButton is not an existing control, we have to create the component first.

Before we do that, we need to set namespace for the custom components in the root tags. While we're at it, set showStatusBar to false, creationComplete event handler to init(), minWidth and minHeight to 400 and width and height to 600 and 500.

<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx" 
   xmlns:custom="*"
   showStatusBar="false"
   creationComplete="init();" minWidth="400" minHeight="400"
   width="600" height="500">

Create a new file in the same directory as Main.mxml. Call it IconButton.mxml.

<?xml version="1.0" encoding="utf-8"?>
<s:Button xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" skinClass="iconSkin">

<fx:Metadata>
[Style(name="icon",type="*")]
</fx:Metadata>

</s:Button>

The class uses a custom skin called iconSkin.

Create a new file called iconSkin.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin name="iconSkin"
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark" 
        minWidth="68" minHeight="68"
        alpha.disabled="0.5">

    <s:states>
        <s:State name="up" />
        <s:State name="over" />
        <s:State name="down" />
        <s:State name="disabled" />
    </s:states>
 
    <fx:Metadata>
        [HostComponent("spark.components.Button")]
    </fx:Metadata>
 
    <s:Rect width="68" height="68" alpha.up="0" alpha.over="0.4" alpha.disabled="0">
<s:fill>
<s:SolidColor color="#ffffff"/>
</s:fill>
</s:Rect>
<s:BitmapImage source="{hostComponent.getStyle('icon')}" top="2" right="2" left="2" bottom="2" alpha.disabled="0.5" />
 
</s:SparkSkin>

Now return to the main mxml file. Let's add one more thing - shadow drop effect for the drawArea object. Add Script tags and create an init() function which sets drawArea's filters to an array of 1 element - DropShadowFilter object.

<fx:Script>
<![CDATA[
import flash.filters.DropShadowFilter;

private function init():void{
drawArea.filters = [new DropShadowFilter(4, 60, 0, 0.7, 10, 10, 1, 3)];
}
]]>
</fx:Script>

And that's all for today.

Full code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx" 
   xmlns:custom="*"
   showStatusBar="false"
   creationComplete="init();" minWidth="400" minHeight="400"
   width="600" height="500">

<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>

<fx:Script>
<![CDATA[
import flash.filters.DropShadowFilter;

private function init():void{
drawArea.filters = [new DropShadowFilter(4, 60, 0, 0.7, 10, 10, 1, 3)];
}
]]>
</fx:Script>

<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#ccccdd" width="100%" height="68">
<custom:IconButton icon="@Embed('../lib/bubble.png')" toolTip="Annotation" enabled="true" />
<custom:IconButton icon="@Embed('../lib/bubble.png')" toolTip="Annotation" enabled="false" />
</mx:HBox>
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="on" verticalScrollPolicy="on">
<mx:Box backgroundColor="#eeeeee" width="100%" height="100%" verticalAlign="middle" horizontalAlign="center" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:Box id="drawArea" backgroundColor="#ffffff" width="300" height="200">
<s:VGroup width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
<s:Label fontSize="24" color="#444444">Welcome to KirAnnotator.</s:Label>
<s:Label fontSize="24" color="#444444">Start by</s:Label>
<s:Label fontSize="24" color="#6666ff">importing a picture!</s:Label>
</s:VGroup>
</mx:Box>
</mx:Box>
</mx:Canvas>
</s:VGroup>

</s:WindowedApplication>

Thanks for reading!

2 comments:

Sharat Achary said...

Having no prior experience in flex, I am learning by going through your tuts on daily basis.

Could you possibly draw a thumb rule, when to use mx components and when to use sparks component, I am bit confused?

what would you suggest as a primer on flex, for a starter like me?

Humble Regards,
Sharat

Kirill Poletaev said...

You can use both mx and spark components, of course. The difference between them is that spark components are initially designed to be more flexible, so that developers can easily edit them to make their own components.

MX components are more complex and have more features, but don't allow such easy customization as spark components do.

Post a Comment