Thursday, January 26, 2012

Creating a Flex AIR Screenshot app: Part 5

Today we'll add more content and create image buttons for the start screen in our application.

First go to the crop NavigatorContent object. Above the HTML tags, add a new HBox object, color it and set its parameters like shown below.

<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">

</mx:HBox>

Inside of it, add 2 buttons - one will be Back, another will be Continue. Set the second one's enabled property to false for now, and the first one's click event handler to {stack.selectedChild = loadpage}. This way the user can use this button to return to the first screen:

<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage}" />
<s:Button label="Continue" enabled="false" />
</mx:HBox>

Make sure the content of this NavigatorContent object is in a VGroup with 100% size and gap set to 0.

<s:NavigatorContent id="crop">
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage}" />
<s:Button label="Continue" enabled="false" />
</mx:HBox>
<mx:HTML width="100%" height="100%" id="cropHTML" />
</s:VGroup>
</s:NavigatorContent>

Now, let's add some icons for our 2 buttons on the first step screen! There will be 4 images in total - 2 for Cut and 2 for Screenshot buttons (normal and rolled-over states).

Here are the ones I made:

b_cut.png

b_cut_over.png

b_screenshot.png

b_screenshot_over.png

Put them in the "lib" directory of your project.

Now we'll create a component that we will be able to use as a Button with images instead of normal labels.

First we go to WindowedApplication tags and declare a new namescape "custom" like this:

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

The * symbol means that the components are located in the same directory as main mxml file. So, create a new mxml file in the same directory and give it a name of ImageButton.mxml.

It is going to be a component that's based off the normal Button class, so the root tags are Buttonn. Create Metadata tags and 2 style lines to set new custom properties - img and over.

<?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="imageSkin">

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

</s:Button>

As you can see, I also set the skinClass property of the root Button tags to imageSkin. Create a new mxml file called imageSkin.mxml in the same directory.

It's a skin that we will use to display images in the buttons. We can use a BitmapImage object to do that and set its source and source.over properties:

<?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" 
        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:BitmapImage source="{hostComponent.getStyle('img')}" source.over="{hostComponent.getStyle('over')}" />
 
</s:SparkSkin>

Now go to the main mxml file. Change the buttons into image buttons in the first NavigatorContent object like this:

<s:NavigatorContent id="loadpage">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Enter the link to the page:</s:Label>
<s:HGroup>
<s:TextInput width="250" id="urlInput" /><s:Button label="Browse local..." click="doBrowse();" />
</s:HGroup>
<s:HGroup>
<custom:ImageButton img="@Embed('../lib/b_cut.png')" over="@Embed('../lib/b_cut_over.png')" toolTip="Crop area" click="goCrop();" buttonMode="true" />
<custom:ImageButton img="@Embed('../lib/b_screenshot.png')" over="@Embed('../lib/b_screenshot_over.png')" toolTip="Take screenshot" buttonMode="true" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>

And now we have working image buttons! Looks pretty!

One more thing to do in this tutorial: edit changeStat() function by adding 1 line to the first conditional - we need to set urlInput.text value to urlString when the page changes to loadpage.

private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
}
}

And now, the 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:custom="*"
                       xmlns:mx="library://ns.adobe.com/flex/mx" showStatusBar="false"
   width="450" height="300" creationComplete="init();">
   
   
<fx:Declarations>
<mx:ArrayCollection id="headerTitles">
<fx:Object step="Step one:" description="load a web page." />
<fx:Object step="Step two:" description="set your export preferences." />
<fx:Object step="Step two:" description="select the area you wish to crop." />
<fx:Object step="Step three:" description="set your export preferences for the cropped image." />
<fx:Object step="Final step:" description="please wait while your images are being expored." />
</mx:ArrayCollection>
</fx:Declarations>

<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

.descriptionText{
fontSize: 24;
color: #fff;
}

#headStep{
fontSize: 30;
fontWeight: bold;
color: #ffffbb;
}

#headDesc{
fontSize: 30;
color: #ffffff;
}
</fx:Style>

<fx:Script>
<![CDATA[
import flash.events.Event;
import flash.filesystem.File;
import flash.net.URLRequest;
import mx.events.FlexNativeWindowBoundsEvent;

private var urlString:String;

private function init():void {
addEventListener(FlexNativeWindowBoundsEvent.WINDOW_RESIZE, onResize);
}

private function doBrowse():void{
var file:File = new File();
file.addEventListener(Event.SELECT, browseSelect);
file.browseForOpen("Load a webpage");

function browseSelect(evt:Event):void {
urlInput.text = file.nativePath;
}
}

private function goCrop():void {
stack.selectedChild = crop;
urlString = urlInput.text;
}

private function changeState():void {
if (stack.selectedChild == loadpage) {
contentBox.setStyle("horizontalAlign", "center");
urlInput.text = urlString;
}
if (stack.selectedChild == crop) {
maximize();
contentBox.setStyle("horizontalAlign", "left");
cropHTML.htmlLoader.load(new URLRequest(urlString));
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
}
}

private function onResize(evt:Event):void {
if (stack.selectedChild == crop) {
cropHTML.width = contentBox.width;
cropHTML.height = contentBox.height;
}
}
]]>
</fx:Script>
   
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#333333" height="46" width="100%" paddingTop="10" paddingLeft="10">
<s:Label id="headStep" text="{headerTitles.getItemAt(stack.selectedIndex).step}" />
<s:Label id="headDesc" text="{headerTitles.getItemAt(stack.selectedIndex).description}" />
</mx:HBox>
<mx:Box backgroundColor="#666666" width="100%" height="100%" id="contentBox" horizontalAlign="center">
<mx:ViewStack id="stack" change="changeState();">
<s:NavigatorContent id="loadpage">
<s:VGroup width="100%" horizontalAlign="center" paddingTop="20">
<s:Label styleName="descriptionText">Enter the link to the page:</s:Label>
<s:HGroup>
<s:TextInput width="250" id="urlInput" /><s:Button label="Browse local..." click="doBrowse();" />
</s:HGroup>
<s:HGroup>
<custom:ImageButton img="@Embed('../lib/b_cut.png')" over="@Embed('../lib/b_cut_over.png')" toolTip="Crop area" click="goCrop();" buttonMode="true" />
<custom:ImageButton img="@Embed('../lib/b_screenshot.png')" over="@Embed('../lib/b_screenshot_over.png')" toolTip="Take screenshot" buttonMode="true" />
</s:HGroup>
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="screenshotsettings">

</s:NavigatorContent>

<s:NavigatorContent id="crop">
<s:VGroup width="100%" height="100%" gap="0">
<mx:HBox backgroundColor="#999999" width="100%" height="24" verticalScrollPolicy="off" verticalAlign="middle" paddingLeft="2">
<s:Button label="Back" click="{stack.selectedChild = loadpage}" />
<s:Button label="Continue" enabled="false" />
</mx:HBox>
<mx:HTML width="100%" height="100%" id="cropHTML" />
</s:VGroup>
</s:NavigatorContent>

<s:NavigatorContent id="cropsettings">

</s:NavigatorContent>

<s:NavigatorContent id="export">

</s:NavigatorContent>
</mx:ViewStack>
</mx:Box>
</s:VGroup>

</s:WindowedApplication>

Thanks for reading!

No comments:

Post a Comment