Archive for Flex 4
CSS Changes in Flex 4
Posted by: | CommentsI recently purchased the book Adobe Flash Builder 4 and Flex 4 by David Gassner and will be publishing a complete review when I’m done with the book. I’m going through it looking for the coverage I feel would be most helpful for those experienced with Flex 3. Even more specifically, those like myself, who have been so busy with contracting work (because Flash is dead of course, and the only way to make a living as a contractor anymore is with HTML5 and CSS3) that they were only able to sample Gumbo during its development.
One such topic, which I happen to be going through now, are the additions to Flex 4’s CSS implementation over Flex 3. This information is available in a number of other places, so this post is more to help me internalize it than to be groundbreaking to everyone else.
1. CSS Namespaces
In order to support type selectors with the same name, CSS namespaces have been introduced. In Flash Builder selecting New->CSS File will show you what the syntax for declaring a CSS namespace is.
@namespace s "library://ns.adobe.com/flex/spark"; @namespace mx "library://ns.adobe.com/flex/mx";
If you’re not going to be using both Spark and Aeon/Halo in your application, you can declare the “default” namespace by omitting the prefix. Namespaces are used as follows:
s|Label { }
mx|Label { }
The lack of any white space between the namespace and the bar, and between the bar and the type selector is significant. Don’t include any white space there. Namespaces will need to be declared even for your custom components (I have a feeling this is going to get messy, but it’s for a good cause.)
2. Descendant Selectors
If you run into a situation where you want to use type selectors, but only when it is used in a particular container, you can use the descendant selectors. You can use them with your custom containers as well. The following declaration will affect all RichText editors contained within a Group:
s|Group s|RichText { color: #0000AA; }
This is another feature that could get out of hand, so use it wisely. Also don’t confuse this with declaring multiple type selectors on the same line, separating them with commas. Like this:
s|Group, s|RichText { color: #0000AA; }
3. ID Selectors
The ID selectors are similar to style name selectors. Recall with a style name selector, the CSS declaration has a name beginning with a ‘.’ and in the MXML declaration of the component you can use styleName="smallText", or something like that.
To use the ID selector, the styleName in the CSS is set to the id of the component you’re styling, prefixed with the # symbol. Like this:
<!-- The MXML Component --> <s:Label id="labelA" />
/* The CSS declaration */
#labelA { color: 0xFF00FF; }
Be sure you set the id explicitly in the MXML– this will not work if you have declared the component in ActionScript.
And that concludes my synopsis of the most important additions to CSS in Flex 4.
Dotted Underline LinkButton (Flex)
Posted by: | CommentsI needed a link control that would display a dotted-underline on hover. To achieve this I overrode the rollOverHandler and the rollOutHandler of a standard LinkButton. Inside the rollOverHandler I used the graphics API to draw a dotted underline beneath the control’s textField.
Here’s an example:
There are some magic numbers, but tweaking them to get the look you want shouldn’t be too difficult.
And here’s the source: DottedLinkButton.as
Contextual Shortcut Manager
Posted by: | CommentsI’m about ready to sleep on my ShortcutManager, I figured I might as well finish off the series. I added context to it, while still maintaining backward compatibility with the non-context enabled version. I don’t think I posted it, so it probably won’t matter so much to my readers. For those who haven’t read the previous posts on my ShortcutManager, the “context” I’m referring to is the context in which a keyboard shortcut might be used; such that a given shortcut might have several functions associated with it depending on its context.
In short I needed four things to implement the context aware shortcut manager.
1. The IKeyboardContext interface
This is a simple interface that a model or class can implement that allows a keyboardContext to be set and retrieved. A keyboardContext is simply a string that identifies the current context. These contexts will be associated with a shortcut in the manager. Here is the entire interface:
package com.googolflex.gflib.interfaces {
public interface IKeyboardContext {
[Bindable(event="propertyChange")]
function get keyboardContext() : String;
function set keyboardContext(v : String) : void;
}
}
2. A reference to an IKeyboardContext needed to be added to the ShortcutManager
As the keyboardContext changes in the model, the ShortcutManager needs to be able to access it, so it can retrieve the correct function for a given keycode-flags-context tuple. The IKeyboardContext was left null, which helps with the backward compatibility (the implementer will be forced to set it if she wants to use it). Here is the line I added, which is pretty trivial:
public static var model : IKeyboardContext = null;
3. Add the context to the addShortcut method
I gave it a default value, which incidentally was “default”, so that every function added to the Dictionary would have some kind of context. Here is the new addShortcut() method:
public static function addShortcut(keycode : uint, func : Function, flags : uint, context : String = "default") : void {
if (flags > 0 && flags < 8)
functionMap[keycode + "-" + flags + "-" + context] = func;
}
4. Finally, the shortcutHandler() needed to incorporate the context
I first check if the IKeyboardContext is null, if it is I know to use “default” as the context. If no context was ever specified, and no IKeyboardContext was ever set, then it still works. Here is the modified code:
public static function shortcutHandler(event : KeyboardEvent) : void {
var flags : uint = getFlags(event);
var context : String = (model!=null) ? model.keyboardContext : "default";
if ( functionMap[event.keyCode + "-" + flags + "-" + context] != null )
(functionMap[event.keyCode + "-" + flags + "-" + context] as Function).apply();
}
And was pretty much it. I will post the modified code, along with a demonstration application at the end of the post. I do want to make a couple points to be aware of when actually incorporating this into a project.
First, your model/class will need to implement IKeyboardContext. Second, you need to remember to set ShortcutManager.model = myIKeyboardContext somewhere. Third, you’re on your own when it comes to maintaining your context. Maybe the “SimpleContextManager” will be next, who knows? And fourth, you’ll have to specify a context when you call addShortcut(). Remember if you download the demo, it will need to have some kind of reference to the ShortcutManager code.
Simple Flex ShortcutManager (revisited)
Posted by: | CommentsI’ve put some more thought into my shortcut manager, and have decided on a way to implement the shortcut context, as well as curb the Dictionary explosion that my previous architecture would have had.
The new version uses one Dictionary to store all functions, the keyCode, combo keys, and context is all encoded into the dictionary key. To illustrate here is my new addShortcut() method:
public static function addShortcut(keycode : uint, func : Function, pair : String) : void {
var flags : int = getFlagsFromString(pair);
if (flags > 0)
functionMap[keycode + "-" + flags] = func;
}
It accepts the same parameters, the only difference is that the pair string is now a dash delimited string, containing the key combinations (i.e. “ctrl“, “ctrl-alt“, “shift-ctrl“, etc). Those are parsed by a method getFlagsFromString() which I will probably get rid of in favor of some named constants on the ShortcutManager class. That will eliminate the need for the additional method, and pair (which will be one of said constants) can be added to the key as-is.
The removeShortcut() is very similar. I haven’t implemented “contexts” yet, but you can visualize how it will be done:
functionMap[keycode + "-" + flags + "-" + context] = func;
Now that there is only one Dictionary, the shortcutHandler() method has become almost trivial. Here it is, in all of its 5-lined glory:
public static function shortcutHandler(event : KeyboardEvent) : void {
var flags : uint = getFlags(event);
if (functionMap[event.keyCode + "-" + flags] != null)
(functionMap[event.keyCode + "-" + flags] as Function).apply();
}
Like I said… trivial.
Using Bit-wise Math to Simplify Logic
Posted by: | CommentsStrictly speaking, bit strings are not nearly as easy to understand as named boolean variables; but there are situations when they can simplify or eliminate the need for long boolean expressions.
Consider my recent post about the ShortcutManager. There are three control keys that may or may not be pressed at any given time. This amounts to 8 possible key combinations (7 if you ignore when none of them are pressed). Here’s what this would look like if you used a boolean expression to check for each of the possible combinations:
var ctrl : Boolean = event.ctrlKey;
var alt : Boolean = event.altKey;
var shift : Boolean = event.shiftKey;
if (!shift && !alt && ctrl) {
// CTRL
}
else if (!shift && alt && !ctrl) {
// ALT
}
else if (!shift && alt && ctrl) {
// CTRL-ALT
}
else if (shift && !alt && !ctrl) {
// SHIFT
}
else if (shift && !alt && ctrl) {
// CTRL-SHIFT
}
else if (shift && alt && !ctrl) {
// SHIFT-ALT
}
else if (shift && alt && ctrl) {
// CTRL-SHIFT-ALT
}
That might not seem too bad, and it isn’t that hard to understand what’s going on (even without the comments). But what happens when you’ve got 4 variables (16 possibilities)? The number of combinations increase exponentially. Even if the combinations you are actually interested in are sparse, who wants to type out 10 lines each with 32 boolean variables?
With a simple method to construct my “bit string”, we can greatly simplify this. ActionScript doesn’t have a binary number type, so you’ll have to use integers. If you can count by powers of two you won’t have any trouble. Here’s a method that constructs my “bit string” integer based on selected control keys:
private static function getFlags(event : KeyboardEvent) : uint {
var flags : uint = 0;
flags += (event.ctrlKey) ? 1 : 0;
flags += (event.altKey) ? 2 : 0;
flags += (event.shiftKey) ? 4 : 0;
return flags;
}
Having this integer allows me to simplify the logic as follows (which isn’t harder to understand at all, if you use comments):
switch ( getFlags(event) ) {
case 1: // CTRL
break;
case 2: // ALT
break;
case 3: // CTRL-ALT
break;
case 4: // SHIFT
break;
case 5: // CTRL-SHIFT
break;
case 6: // SHIFT-ALT
break;
case 7: // CTRL-SHIFT-ALT
break;
}
This is powerful, but it’s just scratching the surface. I haven’t even discussed the bitwise operators &, | and ^. Or the bitwise shift operators >> and <<. These come in handy when you store a series of options as a bit string and need to test whether a certain option is on or off.
For example, if we needed to test if value returned by getFlags() had the SHIFT bit set, we could use the following boolean expression to test it. Remember SHIFT = 4:
if (getFlags(event) & 4 == 4)
Of course this doesn’t help us out much now in the ShortcutManager, but assume I was to add 3 possible contexts that these shortcuts might be used in (different screens, for example). They would hold the 8, 16, and 32 bit places. I could use bitwise math to split them if I only needed to manipulate one them at a time (a stretch, I know).
var screenOnly: uint = flags & 56; var keysOnly: uint = flags & 7;
They have a variety of uses and are there when you need them. There’s an excellent explanation of various bitwise operations and their uses here.
Simple Flex ShortcutManager
Posted by: | CommentsJust for fun I wrote a simple ShortcutManager this evening, it turned out to be an interesting little project and taught me a few things about Functions. It’s by no means finished, I’ll detail a few planned improvements after I go over it’s usage.
My goals were to have a static registry that the application could register a keyCode, along with a qualifying key combination (I refer to this as “pair” in the code) like CTRL, or CTRL-ALT. I left out ALT, as Windows seems to have issues with giving up control of the ALT key when used alone. Along with the keyCode, I needed to be able to register a function that would be called when the key combination was pressed. I also wanted to be able to remove a key combination at runtime.
My data structure was simple, I used a separate Dictionary for each of the key combinations I was supporting.
private static var ctrlFunctionMap : Dictionary = new Dictionary(); private static var ctrlAltFunctionMap : Dictionary = new Dictionary();
I wrote an addShortcut method that accepted the keyCode integer, the function to be called, and a string declaring the combination key(s). In it I simply associated the keycode and the function in the appropriate Dictionary. Here is the addShortcut():
public static function addShortcut(keycode : uint, func : Function, pair : String = "ctrl") : void {
if (pair == "ctrl") {
ctrlFunctionMap[keycode] = func;
}
else if (pair == "ctrlAlt") {
ctrlAltFunctionMap[keycode] = func;
}
else {
trace("Key combination not supported.");
}
}
The removeShortcut() method has a similar structure, with one less parameter since we don’t need to know the function. We simply set the appropriate function for the appropriate keycode and combination key to null. Here is the removeShortcut() function:
public static function removeShortcut(keycode : uint, pair : String = "ctrl") : void {
if (pair == "ctrl") {
ctrlFunctionMap[keycode] = null;
}
else if (pair == "ctrlAlt") {
ctrlAltFunctionMap[keycode] = null;
}
else {
trace("Key combination not supported.");
}
}
Finally we need a method that accepts a KeyboardEvent and determines if one of the functions needs to be executed, and then call it. Here is the shortcutHandler() function that does this:
public static function shortcutHandler(event : KeyboardEvent) : void {
if ( event.ctrlKey && !event.altKey && (ctrlFunctionMap[event.keyCode] != null) ) {
(ctrlFunctionMap[event.keyCode] as Function).apply();
}
else if (event.ctrlKey && event.altKey && (ctrlAltFunctionMap[event.keyCode] != null) ) {
(ctrlAltFunctionMap[event.keyCode] as Function).apply();
}
}
I learned an important lesson when I first tried to implement this method. I tried casting the value from the map as a Function, like this:
Function(ctrlFunctionMap[event.keyCode]).apply();
which didn’t work, and spat the error:
EvalError: Error #1066: The form function('function body') is not supported.
Fortunately, one of ActionScript’s more descriptive error messages (I could tell by the parentheses what was wrong) and was able to correct it using the as operator. I didn’t try it, but I might have been able to not bother casting it at all.
Here’s my ShortcutManagerDemo application, demonstrating how it can be used with a variety of functions and function literals.
import com.googolflex.gflib.managers.ShortcutManager;
private function onCreationComplete() : void {
ShortcutManager.addShortcut(89, onCtrlY, "ctrl");
ShortcutManager.addShortcut(89, onAltY, "ctrlAlt");
var f : Function = function():void { trace("Ctrl-U pressed."); }
ShortcutManager.addShortcut(85, f, "ctrl");
ShortcutManager.addShortcut(85,
function():void { trace("Ctrl-Alt-U pressed."); },
"ctrlAlt");
}
private function onAddedToStage() : void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, globalShortcutHandler);
}
private function globalShortcutHandler(event : KeyboardEvent) : void {
ShortcutManager.shortcutHandler(event);
}
private function onCtrlY() : void {
trace("Control-Y pressed.");
}
private function onAltY() : void {
trace("Ctrl-Alt-Y pressed.");
}
I’ll post the code for the manager, and the sample application at the end of the post. Anyway, some improvements I’m planning…
I’d like to associate a context with each command, so that the same keyCodes could be used on different screens. Organizing the manager for such functionality doesn’t strike me as being that hard. I would have to make some changes to my logic to keep down the “conditional explosion”. The daunting part is where to get the context state… I’ll probably end up creating an interface for it, and then make my models implement it.
Of course I’d like to add more combination keys: SHIFT, SHIFT-ALT, CTRL-SHIFT-ALT, etc. The challenging part for that will be simplifying the conditional logic in shortcutHandler() to keep from having to check for a billion cases. I think I would start by pushing the (ctrlFunctionMap[event.keyCode] != null) check down a level, and using my first level of logic only to check the combination keys pressed.
Anyway, if this is useful for anyone I’m glad I could help. Here’s the source:
ShortcutManagerDemo.mxml
ShortcutManager.zip
Update (8/18/09): I added a few things to ShortcutManagerDemo.mxml, namely an interface that allows the user to add their own key commands at runtime. This has limited usefulness in it’s present form, as the functions themselves are still fixed at compile time. Here are some keycodes you can try it out on, anyhow.
a-65; b-66; c-67… 0-48; 1-49; 2-50…
Extending the SkinnableComponent (well, sort of)
Posted by: | CommentsI won’t exactly be extending a SkinnableComponent in this post, I’ll be extending the Button (which extends SkinnableComponent) and creating a few new skins for it. Extending the SkinnableComponent is almost identical to extending the SkinnableContainer (see my previous post). You won’t need the contentGroup, of course.
I wanted to illustrate the power of Flex’s new skinnable architecture when combined with states.
Specifically I will show:
1. How easy it is to create multiple skins for the same class.
2. How easy it is to change skins at runtime via states.
For my collapsible panel, I need a button. All in all the button has 8 possible states: for each of the two expanded or collapsed states of the container, there are the 4 possible button states (up, down, over, disabled). Rather than suffer the madness of creating a skin with 8 possible states and the button class to manage them, I’m going to create two skins (one for expanded, one for collapsed), each which use the 4 standard button states.
I’ll include the full code for the CollapseButtonSkin, (which extends Skin). The code for ExpandButtonSkin is almost identical, except for the image names. The most important thing to note, is how I change the source of the Image using the new state syntax. I’ll be using that same syntax later in my panel.
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="12" minHeight="12" alpha.disabled="0.5">
<!-- host component -->
<fx:Metadata>
[HostComponent("com.googolflex.gflib.controls.ExpandCollapseButton")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<mx:Image
source.down="@Embed('../assets/collapse_panel/collapse_down.png')"
source.over="@Embed('../assets/collapse_panel/collapse_over.png')"
source.up="@Embed('../assets/collapse_panel/collapse.png')"
source.disabled="@Embed('../assets/collapse_panel/collapse_over.png')" />
</s:Skin>
I didn’t do anything special in the ExpandCollapseButton class, I just extended Button (which contains the code to change between the up, down, over, and disabled states).
When I add my button to the QuickCollapsePanelSkin class, I specify a skinClass for each of my two panel states. When the state of the component changes, the button skins (which in turn have their own states) will be updated automatically. Here is the code:
<controls:ExpandCollapseButton
width="12" height="12"
top="{(SimpleQuickCollapsePanel(hostComponent).headerHeight - 12) / 2}"
left="4"
skinClass.collapsed="com.googolflex.gflib.skins.ExpandButtonSkin"
skinClass.expanded="com.googolflex.gflib.skins.CollapseButtonSkin"
click="SimpleQuickCollapsePanel(hostComponent).toggleExpanded()" />
You can download the full source for this example here: simple_collapsible_panel.zip
Extending the SkinnableContainer (attempt 1)
Posted by: | CommentsI’ve just created my first Flex 4 component, and loved doing it. It’s not entirely finished, but I wanted to share what I learned for those who may follow after me.
In the component proper, some things to remember:
1. Extend SkinnableContainer.
2. Declare the skin states using metadata brackets. In my case:
[SkinState("collapsed")][SkinState("expanded")]
3. Override getCurrentSkinState() to return one of the strings declared in #2, based on component state.
override protected function getCurrentSkinState() : String { if (expanded) return "expanded"; else return "collapsed";}
4. Call invalidateSkinState(), if necessary. Possibly done in setters or in commitProperties()
In the skin class, some things to remember:
1. Extend the SkinnableContainerSkin.
2. Declare the host component, the component you are skinning. Done as follows, using metadata tags:
<fx:Metadata>
[HostComponent("com.googolflex.gflib.containers.SimpleQuickCollapsePanel")]
</fx:Metadata>
If you need to access any properties of the extended class, ie SkinnableContainer you can do so by using the hostComponent variable. When I wanted to access members specific to my HostComponent, I had to cast hostComponent to a SimpleQuickCollapsePanel.
3. Declare the states of your skin. This may be done as follows:
<default:states> <mx:State name="collapsed"> <mx:State name="expanded"> </default:states>
4. Draw your layers or add your images to the skin as necessary. Reference your states, or hostComponent as necessary.
5. In the case of the SkinnableContainer you’ll want to make sure you add the container for its children. You can supply whatever layout you need, and can even change it based on state. It needs to be called contentGroup, however.
Here’s an example of how I did it:
<s:Group id="contentGroup"
left="3" right="3"
top="{SimpleQuickCollapsePanel(hostComponent).headerHeight+3}"
bottom="3"
visible="{SimpleQuickCollapsePanel(hostComponent).expanded}">
<s:layout>
<s:VerticalLayout />
</s:layout>
</s:Group>
I’ll be including the full source for my QuickCollapsePanel in my next post, where I describe extending the SkinnableComponent.
Update: In the most recent SDK release, the spark.skins.default package has been changed to the spark.skins.spark package. This affects the SkinnableContainerSkin class.
Stay tuned for the next update, when Adobe changes it to the spark.skins.spark.skins package…
Flex 4 and States (they finally got it right)
Posted by: | CommentsI’ve finally started a serious investigation into Flex 4. Unfortunately it takes me a while to get around to these things, especially in the middle of a project with 2 developer casualties thus far. The project is winding down a bit, the interaction designers are finally off the project, and I’ve had a bit more time to turn my attention to other things. It couldn’t have happened at a better time, either, since I’ll be giving a Flex 4 presentation at the local user group meeting this coming Tuesday (specifically on the MVC changes involving Flex components).
Anyway, I just have to say I am very impressed with the new “states” implementation. Though in many ways it’s still the same old states we had with Flex 2 and 3, the approach is much cleaner and much more in line with how such a feature should be used.
What has had the greatest effect is the separation of component behavior from component appearance. With this new separation comes a much clearer understanding that states are intended to manage component state. I think this must be what the architects originally introduced states for, but because the way it was implemented this purpose was a lost somewhat.
There’s a fine line between using states as a means to add and remove children from the Application or component based on changing application state, and using them to track component state. There are occasions when application state and component state are the same thing; there are many cases when they are not. The new approach makes it much easier to handle both cases, and to know when to use states and when not to…
Define your states in the component skin, and add a corresponding SkinState metadata tag to your component class. That’s where the states belong… there should be no need to have states or use the currentState property in your component class, though it inherits it from UIComponent.
Based on your data model, or user gestures, you should rely on one of the skins states (or a separate skin altogether) to change the view to match the state. There’s a method called getCurrentSkinState() where this can be handled, and it will be called after invalidateSkinState() is called (perhaps inside commitProperties().
In conclusion, though the nasty, nasty states syntax will become history, states should still be used judiciously.

