Flex with CSS, , " />

FlashPlatformist
Articles, Information, News, & Tutorials for Adobe Flash Platform Developers and Architects

Designing (RED)Wire, Part 3: Advanced Styling Methods for Enhanced User Experience with Adobe Flex and AIR

Introduction

In the last segment, you learned how to leverage CSS to style components for large-scale Flex and AIR applications. In part three of this series, you will discover how to style application components programmatically.

The 3D interactive menu state of the application required some programmatic styling in order to lay out the 3D planes properly in their respective positions

The 3D interactive menu required some programmatic styling in order to position the 3D planes properly

Using the getStyle() and setStyle() Methods

All components derived from the UIComponent base class inherit two methods, called getStyle() and setStyle(). These two methods provide an incredible amount of flexibility to the developer, especially for programmatic skinning. Although covering all the possible uses of this functionality is beyond the scope of this article, I will show you a couple of different uses of it to demonstrate the power behind this functionality, as follows:

private function toMinimized():void {
	   TaskBarManager.addToTaskBar(this);
	   pushStateProperties(stateMin, x, y, 200, titleBar.height, NaN, NaN);

	   minimizeButton.setStyle("upSkin", getStyle("restoreButtonUpSkin"));
	   minimizeButton.setStyle("disabledSkin", getStyle("restoreButtonDisabledSkin"));
	   minimizeButton.setStyle("downSkin", getStyle("restoreButtonDownSkin"));
	   minimizeButton.setStyle("OverSkin", getStyle("restoreButtonOverSkin"));

	   maximizeButton.setStyle("upSkin", getStyle("maximizeButtonUpSkin"));
	   maximizeButton.setStyle("disabledSkin", getStyle("maximizeButtonDisabledSkin"));
	   maximizeButton.setStyle("downSkin", getStyle("maximizeButtonDownSkin"));
	   maximizeButton.setStyle("OverSkin", getStyle("maximizeButtonOverSkin"));

	   dispatchEvent(new Event("minimize"));
}

The toMinimized method seen in the code listing above is taken from a custom component that extends the Flex Panel class, and gives the appearance of a new window within the application that can be minimized so that only the title bar is showing in case the user has to access something that is behind it. The cool thing about it, is that when the window is in the minimized state, the minimize button is re-skinned on the fly using the setStyle method, which turns the button into a “restore” button, and the new state for the maximize button skin is also set. Essentially, we are reusing the same instance of a class by using it as a toggle button programmatically. Here is another example, this time using MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	creationComplete="init()">

	<mx:states>
		<mx:State name="MyLibraryState">
			<mx:AddChild position="firstChild">
				<comp:CollectionsLibrary height="100%" width="100%"
					horizontalCenter="0" verticalCenter="0">
				</comp:CollectionsLibrary>
			</mx:AddChild>
			<mx:SetStyle name="backgroundImage"
				value="@Embed(source='com/assets/my_collections_background.png')" />
			<mx:SetProperty target="{vbox1}" name="y" value="442.95"/>
		</mx:State>
	</mx:states>
	(…)

The setStyle method is also conveniently available to the developer through MXML using the syntax: . The code listing above sets a new background image when the state of the application is changed.

Compiling Style Sheets to Load at Runtime

An interesting feature in Flex 3 is that a CSS file can be compiled as a SWF and loaded at runtime. Using this feature, you could allow the user to change the look and feel of your application based on their own personal preference. You may have seen this type of functionality used on social media web sites, where JavaScript is used to swap CSS files when the user selects a new design view.

Not surprisingly, accomplishing this is very easy in Flex. Simply create a new CSS file, place your CSS style selectors in it, and save the file. Then, in the Flex navigator panel (upper left panel when in “Flex Development” mode), right click the CSS file you just created and select the option “Compile CSS to SWF”.

The CSS for the 3D interactive menu was loaded at runtime to layout the 3D planes. In this instance, the CSS information was loaded from a local database and parsed using a custom CSS parser class.

The CSS for the 3D interactive menu was loaded at runtime to layout the 3D planes. In this instance, the CSS information was loaded from a local database and parsed using a CSS parser/helper class

The StyleManager class

After you have created and compiled all of the CSS style sheets that you want to use in your application to separate SWF files, the Flex StyleManager class can be used to easily switch between style sheets, as demonstrated in the following code listing:

private function loadFirstStyleSheet():void {
	StyleManager.loadStyleDeclarations("CSS1.swf");
}

private function loadSecondStyleSheet():void {
	StyleManager.loadStyleDeclarations("CSS2.swf");
}

Computational Expense

One very important thing to take into consideration when loading precompiled style sheets at runtime is the load that you are putting on the user’s system as a result. This method of design implementation should be used conservatively and with extreme caution, as doing a lot of it will quickly degrade the performance of your application due to a lack of available system resources.

Conclusion

In this article series, you have seen a number of methods and techniques for implementing CSS in large-scale Flex applications. Interestingly, the Flash Platform has evolved so much in the last six months, that this article series barely scratches the surface. User Experience Design is taken to the next level with the proliferation of Flash Catalyst and Flash Builder, both of which will be in public beta in a matter of days. Additionally, the Flex 4 SDK expands on the already powerful capabilities of CSS within Flex, making the Flash Platform even more lucrative for RIA development and the number one choice for providing the best possible User Experiences.

Possibly Related Posts:



Posted by Dan Orlando on June 1st, 2009 :: Filed under General, User Experience
Tags :: , ,

Designing (RED)Wire, Part 2: Taking the User Experience from Concept to Production with Flex and CSS

Introduction

In the first segment of this series on designing the user interface of (RED)Wire, you learned about the different techniques and applications of CSS with Flex and AIR applications. In part two of the series, you will learn how these techniques can be applied to application components in enterprise level Flex and AIR applications. You will also discover the value of using external stylesheets when developing your Flex user interfaces.

All of the style information for (RED)Wire was contained in a single, well-commented style sheet. Additionally, all of the assets that were part of the user interface were contained in a single SWF file and loaded on demand.

All of the style information for (RED)Wire was contained in a single, well-commented style sheet. Additionally, all of the assets that were part of the user interface were contained in a single SWF file and loaded on demand.

Applying styles in Flex

Choosing your method of CSS implementation with Flex must be based on the situation and the environment. It is important to look at the application you are designing from the conceptual 50,000-foot view when considering your options for design implementation. The following are the most common methods for using CSS with Flex:

Setting Styles on an Instance (inline)

Flex components that extend the Flex UIComponent base class will allow you to set common styles as properties “inline”, or in other words, within the MXML component declaration tag. The layout properties of a display object are often unique to that object, so it is common to see any one of the following properties set explicitly on a component: x, y, height, width, top, right, left, bottom, horizontalCenter, verticalCenter, horizontalAlign, and verticalAlign.

<mx:Button id="volumeIcon" cornerRadius="0" alpha="0.9"
	verticalCenter="0" enabled="true" toolTip="Volume Control"
	click="toggleVolumeControl();" />

The listing above exhibits a functional example of setting style properties that are unique to the specific instance of the Button component with an id value of volumeIcon. Since I know that this is the only button that will require these particular style values, I have explicitly set the cornerRadius, alpha, and verticalCenter of this particular button.

A good rule of thumb when setting style properties on an MXML component tag is that the only reason you should be setting the property this way is because you know that the particular property value you are setting is specific to that component. For instance, let’s say your application requires a container that vertically stacks display objects, but without any gap in between. At the same time, you know that other VBox containers in the application do need to have some spacing between the display objects. In this type of situation, you should explicitly set the verticalGap property on that instance of the VBox component, as the following listing demonstrates:

<mx:VBox id="myVBox" verticalGap="0"
	x="15" y="15" width="100%" height="100%">

(...)

</mx:VBox>

Embedding CSS in MXML

This method involves embedding styles or assets directly into an mxml file with the tag. For all practical purposes, there are few instances in which directly embedding style information into an mxml file makes sense. It is important to recognize that as the application grows, the design will become harder and harder to maintain if there is a lot of embedded CSS throughout the application. With that in mind, it is important to be conservative with this method and only use it when necessary. The following code illustrates an example of an embedded style declaration that really should be held within an external CSS file for greater code maintainability.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	showFlexChrome="false"
	borderStyle="none"
	keyUp="{this.onKeyStrokeEvent(event);}">

	<mx:Style>
		.bGroup {
			borderSides:"left,bottom,right";
			borderStyle:"solid";
			borderColor:#6d6f71;
			borderLeftThickness:3;
			borderRightThickness:3;
			borderBottomThickness:1;
			dividerColor:#6d6f71;
			dividerThickness:3;
		}
	</mx:Style>

	<mx:Script>
		<![CDATA[ 

			(...)

However, that is not to say that it will never happen. The next code listing is a component based on the Flex AplicationControlBar. In the design that was provided, each button in the control bar is just a single word of text, and looks more like a link than a button.

Notice the seamless integration of the ApplicationControlBar component in the upper right corner (click to view enlarged version).

Notice the Unique Styling of the ApplicationControlBar component in the upper right corner (click to enlarge)

Additionally, each of these one-word links have a small bullet separator between them. Since I had the design for the full application already, I knew this bullet separator was unique to the application’s main control bar and did not appear anywhere else. Most importantly, since the bullet appeared several times within the same component, it made perfect sense to embed the image, as it’s own private class within the MXML file, so that I could bind to it from each of the Image controls that I placed between the links. Otherwise I would have ended up with multiple instances of the same exact image being created, which is nothing more than a waste of system resources.

<?xml version="1.0" encoding="utf-8"?>
<mx:ApplicationControlBar xmlns:mx="http://www.adobe.com/2006/mxml">

 <mx:Script>
        <![CDATA[

            [Embed(source="assets/bullet_black.png")]
            [Bindable]
            private var bullet:Class;            

        ]]>
    </mx:Script>

	<mx:HBox x="10" y="10" id="hbox" horizontalGap="10" width="350">
		<mx:LinkButton label="Help" styleName="appBarButton"/>
		<mx:Image source="{bullet}" />
		<mx:LinkButton label="About" styleName="appBarButton"/>
		<mx:Image source="{bullet}" />
		<mx:LinkButton label="Minimize" styleName="appBarButton" />
		<mx:Image source="{bullet}" />
		<mx:LinkButton label="Quit" styleName="appBarButton"/>
	</mx:HBox>
</mx:ApplicationControlBar>

External Style Sheets

A Flex or AIR Application will have a single MXML file at the root of the source code directory that is based on either the Application class (Flex), or the WindowedApplication class (AIR). This is the default MXML application file that starts with either or . The application’s style sheet source should immediately follow the declaration of the application’s base class, as seen below:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	showFlexChrome="false"
	dropShadowEnabled="false"
	borderStyle="none"
	applicationComplete="{this.appInit(event);}"
	>

	<mx:Style source="com/passalong/assets/RED_SKIN_MAIN.css"/>

	<mx:Script>
		<![CDATA[
			...
                ]]>
        </mx:Script>

The easiest and safest way to maintain the style settings of an application is by using external style sheets. In fact, you could reasonably maintain all of the styles of a large application from a single CSS file. I choose to use only one CSS file for two reasons; first, I always know where to find my style settings, and second, it makes finding styles easy for other developers when working in a team environment. Additionally, it is good practice to keep this file well organized, because as the application grows, your CSS file will inevitably grow as well.

The custom help component went through 5 design iterations. This wasnt a problem though because it was completely driven by CSS.

The custom FAQ component I built went through 5 design iterations. This wasn't a problem though because it was completely driven by CSS (Click to see the functional component).

When building your main application CSS file, it is generally good practice to place your default component style declarations first. For instance, if you want all of your tooltips to look the same throughout your application, use ToolTip as the name of the style and place it toward the beginning of the file. I tend to place a tooltip on just about anything I can in my applications to make the application as user-friendly as possible. Therefore, the tooltip component shows up in my applications more than probably any other component. Since your default component styles have the most impact on the overall look and feel of your application, you need to have quick and easy access to them. This is why it is usually a good idea to place those styles first.

Keep in mind that in most applications, you won’t be able to get away with just creating a default style for each component and calling it a day. The Button component is a good example of this. In order to keep your CSS code tidy, also consider grouping component style subsets together. For instance, a design with three alternate button styles called: Button.musicPlayerPlay, Button.pageDown, and Button.backToMenu, would be placed one after the other in the style sheet and separated by comments from other style groupings.

Conclusion

The bottom line is that in most cases, the most lucrative method for managing and maintaining the design of a Flex user interface is by use of external style sheets. In this regard, Flex is not much different from a standard web application. The methodology is the same: the more you keep styling, layout, and behavior separated from each other, the more manageable your application will be.

Possibly Related Posts:



Posted by Dan Orlando on May 31st, 2009 :: Filed under User Experience
Tags :: , ,

Designing (RED)Wire, Part 1: How to Use CSS to Create Jaw-Dropping User Interfaces with Flex and AIR

Introduction

One of the most powerful features of Adobe Flex is the vast amount of design flexibility that it contains. This is largely due to Adobe’s implementation of Cascading Style Sheets with Flex. For instance, when developing the User Interface of (RED)Wire, an application built on Adobe AIR, I received a number of change requests 2 days before the official launch of the first public release to 160,000 users that were already pre-registered worldwide, eagerly waiting to download their application. While many developers I know would have probably spent the next thirty minutes complaining to fellow developers about how these last-minute requests were an atrocity and an abomination to mankind, I had the changes completed and checked into subversion in less than twenty minutes, thanks to the power of Flex and CSS. It took longer to convince the Technical Director that the changes were complete than it did to complete them.

The main menu State of (RED)Wire, a digital music magazine built with AIR

The main menu state of (RED)Wire, a digital music magazine built with AIR

There are certain inevitabilities that I have learned to expect and prepare for through my experience as a Developer, Architect, and most of all, as a Technical Project Manager.  One such inevitability is that regardless of how much planning is done beforehand, both the design and the functional requirements of a given software project will change, and will change often through the development life cycle (this is the reasoning for the Agile Development methodology, but we’ll save that one for another day).

Change is one of the few certainties when developing large-scale applications in a team-based environment, and the best way to play a winning game is to anticipate the moves of all the players involved and position yourself accordingly before they can make their move. When you learn how to master this development technique, then you are guaranteed to always be in the lead and hitting a moving target (the project requirements) become a lot easier all of a sudden. It is for this reason that I enjoy developing with Flex as much as I do, because Flex features like CSS integration give you the power to do exactly that.

My goal is that by the time you finish reading this series of articles on the design methodologies that I used when creating the (RED)Wire user interface components, you will have learned a number of techniques for utilizing CSS with Flex, particularly with enterprise level applications.

Why Use CSS?

Most object-oriented design patterns keep the design logic separate from behavioral functionality. Since ActionScript is an object-oriented language, it only makes sense to remain consistent with these OOP conventions. The benefits of doing so include: flexibility, keeping maintenance of the application easy as it grows, code reuse, and better performance.

In the world of web design, CSS is a standard for encapsulating the code that makes up the design of a web site. Given the power and maturity of CSS, most experienced web designers strive to implement as much of the design and layout properties of a web site in CSS. The result is much greater control and flexibility over the look and feel of the site. CSS gained most of its popularity approximately three to four years ago when web developers began to realize that when the design of a web site is independent of the site’s behavioral functionalities, the design can be easily modified without the risk of breaking or otherwise negatively impacting the site’s behavioral code. This is what propelled the rapid growth of templates, skinning, and re-skinning the same code base. For example, I am an avid user of WordPress for my blog web site. There are tens of thousands of people that use this same open source code base to power their blog site, and yet, many times you will stumble upon a site built on WordPress and you wouldn’t even know it thanks to it’s impressive separation of code from design through the use of CSS.

Many major magazines use wordpress because of the variety of layouts available thanks to the separation of layout from styling

Magazines use Wordpress largely because of the ability to plug-in new templates on the fly thanks to CSS.

CSS in Flex Improves on what you already know

First and foremost, for those of you coming from a web design background, it is important to understand that Flex CSS does not follow the same conventions as the W3C CSS spec. The hyphen that is used to separate words in the W3C CSS 2.0 specification is not used as part of the code convention in the Flex implementation. Instead, the Flex implementation of CSS uses camel case. For example, vertical-center in the W3C CSS2 spec is equivalent to verticalCenter in Flex CSS. If you are already programming in a language that uses camel case however, this is pretty easy to get used to. The good news is that most of what is available in the CSS 2.0 specification is also available with the Flex CSS implementation. Furthermore, the Flex implementation of CSS expands significantly on the CSS 2.0 W3C standard, offering additional style properties that are unique to the Flex components.

Maintaining Styles – Component vs. Style Properties

Before you begin creating Flex CSS style sheets, I recommend that you first consider how you want your styles implemented. For the sake of simplicity, I am going to show you four basic methods of declaring a style.

Components

A style can be set on a component by using the component’s class name as the style name, like so:

TitleWindow {
   borderColor: #f7f7f7;
   borderAlpha: 1;
   borderThicknessLeft: 0;
   borderThicknessTop: 0;
   borderThicknessBottom: 0;
   borderThicknessRight: 0;
   cornerRadius: 0;
   headerHeight: 0;
   highlightAlphas: 1, 1;
   headerColors: #f7f7f7, #f7f7f7;
   footerColors: #f7f7f7, #f7f7f7;
   backgroundColor: #f7f7f7;
   dropShadowEnabled: true;
}
The TitleWindow component design from (RED)Wire, driven entirely by CSS

The TitleWindow component design from (RED)Wire, driven entirely by CSS

Style Names

Styles can also be declared using a unique style name. Make sure you put a dot in front of it though and use the camel case convention:

.altText {
	fontFamily: TVNordEFCEOP-RegularCon;
	fontSize: 18;
	color: #FFFFFF;
}

Component + Style Name

A style name can also be set on a component when you need to have multiple designs for the same component, which is common for applications that have multiple view states. This also ensures that only the specified component can have that particular style assigned to it:

Text.bigYellowText {
	color:#EFB526;
	fontSize:36;
	fontWeight:Bold;
}

The Global Selector

The global selector is a special kind of selector that will impact every component within the application that contains the properties that are set inside of it. For example, I could set the cornerRadius style property of all of my display object components that contain a cornerRadius style property to a setting of 4, like so:

global {
	cornerRadius: 4;
}

Understanding Style Precedence

While the global selector basically sets a default value of a property, it is easily overridden. For instance, if I set the cornerRadius property of the Button component to 0 either inline or in my CSS file, it will take precedence over the global default setting of 4 that I have also specified, and thus all of my Buttons will contain a cornerRadius value of 0. Furthermore, I can override both the global setting of 4 and the Button setting of 0 by creating an additional style such as:

Button.altCornersButton {
	cornerRadius: 8;
}

Conclusion

Congratulations, you have learned the basics of CSS implementation in Flex and AIR applications. However, there is a lot more to cover. In part two of this series, you will learn how to apply these concepts to application components in an enterprise application development environment, as I did in the implementation of the user interface of (RED)Wire.

Possibly Related Posts:



Posted by Dan Orlando on May 30th, 2009 :: Filed under User Experience
Tags :: , ,

What is User Experience Design?

Recently I’ve been on an endeavor to define “User Experience Design”. This is a concept that is tightly knit with RIA, because RIA places a certain value on user experience that the web has simply never seen before. As a result, there is a lot of confusion surrounding User Experience Design.

An associate sent me a link to a presentation that he attended titled “The 10 Most Common Misconceptions about User Experience Design”, and I found it to be particularly interesting, so I decided to post it here:

Possibly Related Posts:



Posted by Dan Orlando on April 16th, 2009 :: Filed under User Experience
Tags ::

New Papervision3D Portfolio

In response to a number of recent requests that I’ve gotten for an online portfolio, I have posted a “rough draft” preliminary version that uses Papervision3D for a “cover flow” type of effect that is reminiscent of what is probably the most famous addition to Apple’s OSX 10.5 Leopard operating system. Anyway, I plan to add a 5th section for Audio/Video production, but since I want to play the audio and videos directly from the app, I haven’t gotten that far yet. Nonetheless, although this isn’t necessary unique and original (3D carousels and cover flow components and apps have been swimming around the AS3 underground for a little while now), I think this is a pretty neat way to present an online portfolio if you ask me. It sure beats a typical 2D slideshow! 

Since I expect this will be changing a lot over the coming months, I am definitely open to feedback. Click HERE to take a look at it and let me know what you think by leaving comments here.

Here’s a screenshot (click for full size):

 

Papervision3D cover flow portfolio screenshot

Papervision3D cover flow portfolio screenshot

Possibly Related Posts:



Posted by Dan Orlando on April 14th, 2009 :: Filed under Announcements, Tools & Innovation, User Experience
Tags :: ,

3D UI Development – The Bleeding Edge of RIA

I’ve recently been learning a few new programs, particularly Cinema 4D and Swift 3D, in tandem with Apple Motion and Adobe After Effects CS4. I was already a pretty crafty dude with After Effects, but I had never even tapped into a fraction of what it was capable of since there is a bit of a learning curve there.

The thought came to me today as to why I have spent so much time on 3D with ActionScript when doing 3D with these tools is so much easier? My next thought was of course, the obvious answer…These 3D movies I’m making using far superior tools (for 3D design) are static in nature. These movies are quite cool to watch and fun to make, but they lack the 2 things that make ActionScript 3D so intriguing: 1) user interactivity (the thing that makes games so addicting for the “gamer” community), and 2) the ability to make the content dynamically driven by data on a server hundreds or thousands of miles away.

There are a few “blocking points” though that we developers who consider ourselves “the bleeding edge of RIA” still need to address. First, although Flash 10 has undergone substantial improvement for 3D rendering, the code required to produce 3D user interfaces is still complicated and buggy, and it is still not true 3D. The vector-based image sequences deliver the illusion of 3D through the use of carefully placed masks, shadows, gradients, and the relational sizing of objects. This is an incredibly resource intensive process from a hardware standpoint. There is a reason that almost all PC games are still developed using C++, which is the fact that the language gives you direct access to the computer’s hardware and allows the application to make decisions in the way that the interface is displayed based on the hardware resources that are available to it.

By its very nature, the Flash VM is resource-intensive to begin with for the simple fact that it is a virtual machine (the advantage being portability between platforms). This should sound quite familiar to Java enterprise developers, who also sacrifice resources for the advantage of portability. In the enterprise, the answer is always simply “throw more hardware at it” if things start slowing down. In the consumer market however, we face a different predicament developing mainstream 3D interfaces in – say – Adobe AIR. The answer there is not as simple as throwing more hardware at it because A) few consumers know what to get or how to install it, B) computer and hardware vendors purposely limit the upgrade path of computers in the consumer market, and C) this is a terrible idea to begin with and the wrong way to look things. The answer should instead be a matter of making companies like Adobe find ways to make their software more efficient… For example, change the properties of AIR to compile like C++ does instead of the Flash VM. Unfortunately, this is not cost-effective for Adobe or even logical for them at this point, which puts the problem back in the developer’s hands, especially for framework creators like the PaperVision 3D team.

…just food for thought.

Possibly Related Posts:



Posted by Dan Orlando on January 31st, 2009 :: Filed under General, User Experience
Tags :: , , ,

Simple Papervision3D

Add Animated Transitions and Custom Navigation to Your Flex Viewstack Components

One of my biggest issues with the Flex Viewstack element is the lack of built-in transitions to choose from. So in this demonstration, I will show you how to create your own. We will first create a reusable animation factory class that we can call from anywhere in our application. Then, I will demonstrate how we can put the animation factory to work by creating a slide transition for a viewstack component. Note that Flex has a built in Slide object, and if you don’t mind mixing up your ActionScript behaviors with your MXML display, then that is also a viable option worth looking into for accomplishing the same end result. Just like anything you’ll find on this site though, we want to build abstraction and reusability into our code.

Step 1: Create the Animation Factory

Our first step is to create the animation factory class. We can instantiate this object from anywhere in an application and call the animateTo method, passing it the x, y position that we want it to end at, and the duration in milliseconds that we want the animation to last.

ObjectSlider.as

package {

   import flash.display.DisplayObject;
   import flash.events.Event;
   import flash.events.TimerEvent;
   import flash.utils.Timer;
   import flash.utils.getTimer;

   /**
    * @author Dan Orlando
    */
   public class ObjectSlider
   {
        // The object being animated
	private var _target:DisplayObject;
	 // Each time an animation starts we record its start time
	private var _startTime:Number;
	 // The duration of the animation in milliseconds
	private var _duration:Number;
	 // Record the target's start position
	private var _startX:Number;
	private var _startY:Number;
	 //  Record the difference between the starting and ending positions
	private var _deltaX:Number;
	private var _deltaY:Number;

	public function ObjectSlider() { }

   // Starts an animation that moves the target object from its current
   // position to the specified new position over a specified period of time.
	public function animateTo(target:DisplayObject, toX:Number,
           toY:Number, duration:Number):void {
	   //store where the target was when the animation started
	   _target = target;
	   _startX = _target.x;
	   _startY = _target.y;
	   // calculate difference between target's start position
           // and final destination
	   _deltaX = toX - _target.x;
	   _deltaY = toY - _target.y;
	   _startTime = getTimer();
	   //store how long the animation should take
	   this._duration = duration;
	   //update target's position each time a screen update occurs
	   _target.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
	}

   // Updates the target's position on each ENTER_FRAME event
	private function enterFrameHandler(event:Event):void {
	   var elapsed:Number = getTimer()- _startTime;
	   var percentDone:Number = elapsed/_duration;
	   if (percentDone < 1) {
	      updatePosition(percentDone);
	   }
	   else {
	      updatePosition(1);
	      _target.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
	   }
	}

   // Sets the position of the target object
	private function updatePosition(percentDone:Number):void {
	   _target.x = _startX + (_deltaX * percentDone);
	   _target.y = _startY + (_deltaY * percentDone);
	}

   }
}

Step 2: Create the MXML component
For our MXML display component, we will create a simple canvas that initializes a “helper” class that contains all of the behavior and functionality for the component in ActionScript. Note that when we instantiate the helper class, we pass it the current instance of our canvas component as a display object argument using the this keyword. We also place two left and right arrow buttons here, which we will use to move the viewstack back and forward by changing the selectedIndex value of the ViewStack when one of the buttons is clicked.

CustomCanvas.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="750" height="550"
   creationComplete="init()">
   <mx:Script>
      <![CDATA[
      import com.danorlando.util.ViewStackHelper;

      private var _helper:ViewStackHelper;

      private function init():void {
         _helper = new ViewStackHelper(this);
      }
      ]]>
   </mx:Script>

// place additional mxml components that should not be part
// of the viewstack here, like buttons, labels, etc...
   <mx:HBox x="693" y="56" horizontalGap="5">
      <mx:Button x="64" y="13" id="backBtn" styleName="iconButtonBack"
         width="16" height="16"/>
      <mx:Button x="85" y="13" id="forwardBtn" styleName="iconButtonForward"
         width="16" height="16"/>
   </mx:HBox>
</mx:Canvas>

ViewStackHelper.as

package com.danorlando.util
{
   import com.danorlando.display.components.CustomCanvas;
   import com.danorlando.effects.animation.ObjectSlider;
   import flash.display.DisplayObject;
   import flash.events.MouseEvent;
   import mx.containers.ViewStack;

   public class ViewStackHelper
   {
      private var _parent:CustomCanvas;
      private var _viewStack:ViewStack;
      private var _currentIndex:Number;
      private var _slider:ObjectSlider = new ObjectSlider();

      public function ViewStackHelper(canvas:Canvas) {
            _parent = object;
            addListeners();
            createChildren();
      }

   // add event listeners to the forward and back buttons
      public function addListeners():void {
       _parent.backBtn.addEventListener(MouseEvent.CLICK, viewStackBack);
       _parent.forwardBtn.addEventListener(MouseEvent.CLICK, viewStackForward);
      }

   // create and add the viewstack and it's children
      public function createChildren():void {
         _viewStack = new ViewStack();
         _parent.addChild(_viewStack);
         _viewStack.selectedIndex = 0;
         _viewStack.x = 39;
         _viewStack.y = 72;
         _viewStack.width = 675;
         _viewStack.height = 402;
         var vsChild1:Canvas = new Canvas();
         _viewStack.addChild(vsChild1);
      // add other components and params to the 1st index/child here
         var vsChild2:Canvas = new Canvas();
         _viewStack.addChild(vsChild2);
      // add additional components and params to the 2nd index/child here
         var vsChild3:Canvas = new Canvas();
         _viewStack.addChild(vsChild3);
      // add additional components and params to the 3rd index/child here
      // get the first child that is about to be displayed in the viewstack
         var curChild:DisplayObject = _viewStack.getChildAt(_currentIndex);
      // set the x-position of the child to the x-pos of the viewstack + 600
         curChild.x = _viewStack.x + 600;
      // now slide the child into view
         _slider.animateTo(curChild, _viewStack.x-40, 0, 500);
      }

   // event handler for the back button in the parent container
      private function  viewStackBack(event:Event):void {
         if(_currentIndex > 0) {
            _currentIndex = _currentIndex - 1;
            var newChild:DisplayObject = _viewStack.getChildAt(_currentIndex);
         // set the x-position of the new child 600 pixels to the right
            newChild.x = _viewStack.x + 600;
         // use the animateTo method of our animation factory to slide the new
         // child into position
            _slider.animateTo(newChild, _viewStack.x-40, 0, 500);
         // set the new index
            _viewStack.selectedIndex = _currentIndex;
         // set the forward button to visible if it is hidden
            if (!_parent.forwardBtn.visible) {
               _parent.forwardBtn.visible = true
            }
         // if the _currentIndex property is 0, then hide the back button
            if (_currentIndex == 0) {
                _parent.backBtn.visible = false;
            }
         }
      }

   // event handler for the forward button
      private function viewStackForward(event:Event):void {
         // get the highest index value of the viewstack
         var lastIdx:Number = _viewStack.numChildren-1;
         if(_currentIndex < lastIdx) {
            _currentIndex = _currentIndex + 1;
            var newChild:DisplayObject = _viewStack.getChildAt(_currentIndex);
          // place the incoming child 600px to the left
            newChild.x = _viewStack.x - 600;
          // slide the new child into position using our animation factory
            _slider.animateTo(newFaq, _viewStack.x-40, 0, 500);
          // set the new index of the viewstack
            _viewStack.selectedIndex = _currentIndex;
          // make the back button visible if it is hidden
            if(!_parent.backBtn.visible) {
               _parent.backBtn.visible = true }
          // hide the forward button if we are at the last index
            if (_currentIndex == lastIdx) {
               _parent.forwardBtn.visible = false;
            }
         }
      }

   }
}

Ok, so we’ve got a few things going on here in the helper class. The first thing we do is set the Canvas object that was passed in the constructor to our local (i.e. private) canvas property which is of type CustomCanvas. We then add the event listeners to the forward and back buttons of the parent container – which is the Canvas object that was passed in the constructor – with the addListeners method. We then instantiate the ViewStack and add its children with the createChildren method. You will see the use of our animation factory with the call to _slider.animateTo. Notice that we are initially setting the position of the child off to the left or the right, depending on which button was clicked, then we slide the child into place. Lastly, in order to ensure that we never get a runtime error because the forward button was clicked when we were already viewing the last child, or the back button was clicked when we were already on the first child, we simply set the visible property to false for the respective button based on said conditions.

Possibly Related Posts:



Posted by Dan Orlando on October 14th, 2008 :: Filed under Tutorials, User Experience
Tags :: , , , , , , , ,