Day 2: A New State of Affairs

Once I had the simpler classes compiling, I had to move on to getting the user interface developed. I did not want to just copy the original Flex 1.5 version for several reasons.

  • First, I wanted to use Flex Builder 2 to make the components from scratch. I simply wanted the experience of using the design tools.
  • Second, I knew there would be some compatability issues and may be lots of errors. I didn’t want to have to solve every error in all the files just to see something working. Imagine if this were an application that had a hundred components. I would have to make sure they all compiled cleanly, then cross my fingers that it would work. I did not want to face that amount of work (and frustration). So I decided the incremental approach was better.
  • Finally, there are some new features in Flex 2 that I wanted to use and it would be easier to add them to a clean slate than to retrofit them.

The second point is very important, especially if you are porting a working application. If you copy all of your files and think you can just get the compilation errors removed and it will work, think again. In my first day’s experience I found that I had to make some adjustments in how the application was written. And that was with a handful of files. So I believed it would be best to start over, but to use my already working, Flex 1.5 application, as my base. Many of the functions I wrote would still work and I would not have to re-write everything.

First Attempt

States

One of the new features of Flex 2 are states. States are a way of dividing a component into 2 or more related behaviors. For example, in this PhotoSearch application there is the “authorization” state and the “running” state. In the authorization state you see the panels that direct you through the Flickr authorization process. When that is satisfied the application switches to the running state. Likewise on the Search Panel, there is the normal state with just the TextInput field for the tags, the Search button and the Advanced Options button. When you pick the Advanced Options button, the state of the Search Panel changes to show more options. Click the Advanced Options button toggles the Search Panel between these two states.

In the Flex 1.5 version, I used a ViewStack in place of states. But the state concept is much more powerful.

In the Flex 1.5 version of PhotoSearch I used a Tile with a number of Thumbnail components as children. I debated whether or not to use TileList and decided that using a Tile container was easier. In the Flex 2 version I am going to use a TileList for both the Gallery and the Favorites panels. I’m doing it this way not only to be different, but because cell renderers (now called listItemRenderers) are so much easier to write.

I began by creating my main application and the AuthorizationWindow component. Since I knew that I wanted to use states, I also created a PhotoSearch component to handle the running state. In Flex Builder 2 I set up the authorization state to display the AuthorizationWindow and created a new state, “runningState”, to display the PhotoSearch component. I tested this code by simply having the AuthorizationWindow dispatch an event when the button was picked which caused the main application to switch to the running state.

The AuthorizationWindow I initially created just had a button and it was time to modify it. I suddenly realized that this component also had states: the initial state and the “permission granted” state. So I did the same thing: created the first state with the title and text areas and a button. Then I created another state and changed the text and button label. When you get is something like this:

<mx:states>
<mx:State name="runningState">
<mx:PropertyOverride target="{text1}" property="text" value="Return to this window..." />
<mx:PropertyOverride target="{text2}" property="text" value="Once you are done..." />
<mx:PropertyOverride target="{button1}" property="label" value="Complete Authorization" />
</mx:State>
</mx:states>

In Flex 2, when a component’s state is changed, the PropertyOverride instructions are employed – in this case the text is changed and so is the button’s label. If you were to switch back to the initial state, those overrides are removed and the controls revert to their original values.

With the State definition you can also add and remove whole components along with changing components’ properties.

I think you will find states to be a very convenient way to express a control’s multiple personalities, if that’s appropriate. For example, I think the Thumbnails also have 2 states: the one where the “Loading” text is displayed and the other where the image is displayed.

ListItemRenderers

While my goal at the moment is not to run the application, just lay it out, I did want to tinker with some of the new features to see how they work, if they work in this Alpha release, and see how to adopt them to the application. I already tried out states and am happy with how easy they are to work with.

One of the biggest – and best – changes in Flex 2 is the cell renderer, now known as the ListItemRenderer. If you have used cell renderers in Flex 1.5, you can use the essence of your code, but you should create a new component and not port it.

You have many options how how you want to use renderers: there are drop-in components, in line components, and custom components which are like the Flex 1.5 components. I know that I’m going to use TileList this time and so I wanted to know how to create a custom component (I’ll be using it in both the Gallery and Favorites panels). This is my initial Thumbnail:

<mx:Canvas width="104" height="104" xmlns:mx="..." >

<mx:states>
<mx:State name="imageState">
<mx:RemoveChild child="{loadingLabel}" />
<mx:PropertyOverride target="{img}" property="visible" value="true" />
</mx:State>
</mx:states>

<mx:Script>
<![CDATA[
private function showImage() : Void {
currentState = "imageState";
}
]]>
</mx:Script>

<mx:Image id="img" x="2" y="2" source="{dataObject.thumbURL}"
visible="false"
complete="showImage()" />

<mx:Label textAlign="center" id="loadingLabel" text="Loading" x="0" y="40" width="104" />
</mx:Canvas>

You’ll notice the absence of the setValue method and the presence of dataObject. Practically every Flex component can now be used as a renderer because they all implement the IListItemRenderer API. One of the properties the components now have is a dataObject which is set in the instance to be the data for that cell in the list. In the PhotoSearch application it will be the PhotoInfo which will have a property. The ThumbNail will be showing with a “Loading” label and as soon as the image is loaded, it will switch to displaying the image and not the label. At least that’s the idea. We’ll see what happens when I get this running.

I can see a potential problem with this already. What happens when the data changes – I do a new search? As the TileList is given a new set of data, I presume that each instance of the Thumbnail renderer is going to change the dataObject. So how does the state get reset to show the “Loading” message until the images arrive?

After doing some more reading, I think I found the answer: override the setting of the dataObject. If it works, it will be deceptively simple. Here’s what I’ve changed to the Thumbnail.mxml file:

override public function set dataObject( value:Object ) : Void
{
super.dataObject = value;
currentState = "";
}

I took the function signature right out of the Flex 2 documentation. In Flex 2 you have to indicate you are overriding a method (hence the override keyword). The dataObject is passed to the super method and the currentState is reset. With luck, this will work.

DataProvider and Bindable

In Flex 1.5 it was pretty common to use an Array as a dataProvider to a List component, such as the DataGrid. That’s because in Flex, the Array class implements the DataProviderAPI which provides data binding and change events. I Flex 2.0, the Array no longer implements the DataProviderAPI.

Flex 2 provides a more robust set of Collection classes, much like Java. For the Search History (DataGrid) and TileList components, I decided to use the ArrayCollection class since that was most like what I was using and has many of the same functions as the Flex 1.5 DataProviderAPI.

What this means is that when Flickr returns the array of information about the photos which meet the search criteria, I cannot just bind that result, I have to convert it to an ArrayCollection. Fortunately, that turns out to be pretty easy:

import mx.collections.ArrayCollection;
[Bindable]
public var ac:ArrayCollection = new ArrayCollection( photos );

You’ll notice that a) I had to place the [Bindable] metatag above the variable declaration and b) I had to declare the variable public. The latter is a Flex 2 Alpha restriction.

You must place [Bindable] above every variable or class (to include all variables in the class) to tell the Flex 2 compiler for which variables data-binding code variables should be generated; in Flex 1.5 the code was generated for all variables.

Conclusion

Overall the design process went well. There was a bit of time where some of my panels did not have titles when I ran them, but then I discovered the “Run->Clean” option in Flex Builder 2 which did a full recompile and that seemed to have fixed everything.

I needed to write some quick experimental code to get the feel for renderers and dataProviders, and the documentation really helped on that. I only used the simple ArrayCollection, but I can see there are more options now than before.

At this point I have the PhotoSearch application displaying the AuthorizationWindow. When I click the button, it switches to its next state and when I click the Continue button, the application switches to the running state, displaying the three main windows and the trash can.

In the Search Panel I can click the Advanced Button and it causes the other options to appear. And that’s all the program does. The core code in the com.macromedia.flickr package is not tied into this yet. That’s the next task.

Stay tuned.