Skip to content

Posts from the ‘Flash Platform’ Category

27
Apr
2011

A Better Way to Skin the TabNavigator in Flex 3.5

… is to not use TabNavigator at all. Use a ViewStack and RadioButtons in an HBox!

I like doing skinning work in Flex but there certainly are a few components that I often times find easier to just re-engineer than skin. Scroll bars and TabNavigators are some examples of such components. I’ve heard skinning these components has gotten much easier in Flex 4, but alas, all my projects are still being developed in Flex 3.5.

I was recently given the task of skinning a ‘tabbed’ component, which was previously using the TabNavigator. In Flex 3.5, one can assign custom skins for the first, and last tabs, then a repeating skin for any in-between. This is a fairly common setup for tabs, but unfortunately in this particular component each tab needed to be unique. Another caveat of the component was that the tab bar needed to be wider than the views. After struggling once again to skin the TabNavigator to meet my needs, I finally decided that it might be easier to just do a little re-engineering.

In the past I’d done a series of normal Buttons in an HBox and scripted the ‘turn off/on’ for the other buttons. This time I decided to use RadioButtons and it went flawlessly! The script below shows how to do this. I believe this approach could be used in many situations and not require a lot of re-engineering since it can be done entirely in MXML. Another neat feature of this that the TabNavigator doesn’t allow is a ‘intro screen’ that doesn’t necessarily relate to the tabs, like the blank grey view in my example below.

Get Adobe Flash player

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				layout="absolute"
				width="500" height="300">

	<mx:RadioButtonGroup id="fakeTabGroup" />

	<mx:HBox id="radioButtons" width="100%" height="100" horizontalGap="0">
		<mx:RadioButton styleName="tab1"
						group="{fakeTabGroup}" value="1"/>
		<mx:RadioButton styleName="tab2"
						group="{fakeTabGroup}" value="2"/>
		<mx:RadioButton styleName="tab3"
						group="{fakeTabGroup}" value="3"/>
	</mx:HBox>

	<mx:ViewStack id="views"
				  x="0" y="100"
				  selectedIndex="{ (fakeTabGroup.selectedValue as Number) }"
				  width="100%" height="200" >
		<mx:Canvas backgroundAlpha="1" backgroundColor="0x666666" />
		<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
			<mx:Label horizontalCenter="0" verticalCenter="0" text="BATMAN!" styleName="characterName" />
		</mx:Canvas>
		<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
			<mx:Label horizontalCenter="0" verticalCenter="0" text="WOLVERINE!" styleName="characterName" />
		</mx:Canvas>
		<mx:Canvas backgroundAlpha="1" backgroundColor="0x000000" >
			<mx:Label horizontalCenter="0" verticalCenter="0" text="WONDERWOMAN!" styleName="characterName" />
		</mx:Canvas>
 	</mx:ViewStack>

	<mx:Style>
		.characterName {
			fontSize: 24;
			fontWeight: bold;
			color: #FFFFFF;
		}

		.tab1 {
 			up-skin: Embed(source='/style/batman_d.jpg');
			down-skin: Embed(source='/style/batman_u.jpg');
			over-skin: Embed(source='/style/batman_u.jpg');

			selected-up-skin: Embed(source='/style/batman_u.jpg');
			selected-down-skin: Embed(source='/style/batman_u.jpg');
			selected-over-skin: Embed(source='/style/batman_u.jpg');

			upIcon: ClassReference("mx.skins.ProgrammaticSkin");
			overIcon: ClassReference("mx.skins.ProgrammaticSkin");
			downIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
			disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
			selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
		}

		.tab2 {
			up-skin: Embed(source='/style/wolverine_d.jpg');
			down-skin: Embed(source='/style/wolverine_u.jpg');
			over-skin: Embed(source='/style/wolverine_u.jpg');

			selected-up-skin: Embed(source='/style/wolverine_u.jpg');
			selected-down-skin: Embed(source='/style/wolverine_u.jpg');
			selected-over-skin: Embed(source='/style/wolverine_u.jpg');

			upIcon: ClassReference("mx.skins.ProgrammaticSkin");
			overIcon: ClassReference("mx.skins.ProgrammaticSkin");
			downIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
			disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
			selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
		}

		.tab3 {
			up-skin: Embed(source='/style/wonderwoman_d.jpg');
			down-skin: Embed(source='/style/wonderwoman_u.jpg');
			over-skin: Embed(source='/style/wonderwoman_u.jpg');

			selected-up-skin: Embed(source='/style/wonderwoman_u.jpg');
			selected-down-skin: Embed(source='/style/wonderwoman_u.jpg');
			selected-over-skin: Embed(source='/style/wonderwoman_u.jpg');

			upIcon: ClassReference("mx.skins.ProgrammaticSkin");
			overIcon: ClassReference("mx.skins.ProgrammaticSkin");
			downIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedUpIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedOverIcon: ClassReference("mx.skins.ProgrammaticSkin");
			selectedDownIcon: ClassReference("mx.skins.ProgrammaticSkin");
			disabledIcon:ClassReference("mx.skins.ProgrammaticSkin");
			selectedDisabledIcon: ClassReference("mx.skins.ProgrammaticSkin");
		}
	</mx:Style>

</mx:Application>
One Comment
18
Mar
2010

MN.swf Camp April 5th

I will be giving a talk on light weight 3d development for Flash Player at MN.swf Camp on April 5th.

This should be a great event for anyone interested in the Flash Platform!  Come check it out!

http://www.mnswf.com/camp10/index.cfm

No Comments
5
Feb
2010

Flex Camp Phoenix & Wall Street

I had the privilege of speaking at Flex Camp Phoenix last week.  I gave my presentation on an introduction to Flash Player’s built in 3D effects and functionality.

It was a great event!  If you have an opportunity to attend a Flash/Flexp camp I highly encourage it.  There was great presentations for both the beginner to the advanced developer.  I have applied to give this presentation again at SWF Camp10 here in Minneapolis.  Fingers crossed it gets accepted!
The project which I presented is displayed below. Read moreRead more

One Comment
18
Nov
2009

Flex Camp Wall Street

I gave a session “Introduction to Native 3D In Flash Player” at Flex Camp Wall Street this Tuesday.  I’m going to do a bit more cleanup and documentation within my example code and will hopefully have all the slides & code before weeks end.

Thanks to all those who attended the event.  It was a huge success!

One Comment
19
Aug
2009

Presenting tonight at Flash MN

I will be presenting at FlashMN at 6:30pm.

The talk will primarily focus on the challenges of working with Flash Player’s new x/y/z rotations, setting
perspective projections and masking in 3D space.

2 Comments
7
Feb
2009

Flash Player 10 Rotation XYZ Fun

I’ve been playing around a lot with Flash Player 10′s rotation XYZ.  After doing a series of experimentation and actually implementing it into a new project, I had some doubts about Adobe’s implementation of 3D.

Experiment #1: http://blog.dcholth.com/beta/RotTester/RotTester.html

The images are laid out in a grid, with each image’s rotations (XY & Z) being set to the values of the numeric sliders at the top.  As you can see, each image’s perspective looks different, because they are placed in a 3D environment with the ‘camera’ being set to a specific point.  I had a heck of a time figuring out how to set that camera!

If you look at http://livedocs.adobe.com/flex/3/langref/flash/display/DisplayObject.html#rotationX  it says “Indicates the x-axis rotation of the DisplayObject instance, in degrees, from its original orientation relative to the 3D parent container.”

Well, in the example above, each image is placed in its own Canvas – my best guess was that the parent canvas should be its ’3D Container’ so the rotation should be based off of that, but clearly it was basing off some other point at the Application level.

I posted my frustrations with this a few places, and finally fellow Universal Minder, Ryan Graff came to the rescue, with the missing piece:  PerspectiveProjection

Setting the PerspectiveProjection of your target’s Transform will give you the results I believe most developers will be looking for.

Experiment 2: http://blog.dcholth.com/files/PanelTest/PanelTest.html

The image in the TitleWindow on the left has its PerspectiveProjection set to be the center of the TitleWindow, where as the image in the TitleWindow on the right has the default properties.  Notice that dragging the TitleWindow on the right around the screen results in distortion of the image, where the image on the left remains tilted exactly how we want.

Experiment 3: http://blog.dcholth.com/files/RotatorTest/RotatorTest.html

Back to our grid of images, here we set the images PerspectiveProjection to point towards the red dot.  Drag it around the screen to see how it effects how each image is percieved.

In conclusion, I believe that most developers will want to take advantage of the PerspectiveProjection’s properties when working  rotations of UIComponents in 3dSpace.

One Comment
3
May
2008

Extending the State Class

Flex offerers a wide range of utilities to make working with complicated components and applications simpler. One such feature is the use of States. States are often thought of as only visual or GUI related, but in they are perfect for dividing up logic. In my current project I am building a series of learning activities, and some have activities within activities… needless to say it can get complicated quickly. While breaking up the logic into separate components was one option, I didn’t want to have any risk of ‘flashes’ of GUI while pieces are refreshed, moved, or risk messing up data by passing all these pieces around.

I started to build out my activity component using states. One state for when you enter the activity, one for each of the three phases, a cleanup state and finally an exiting state. As I developed the components and created their enterState and exitState functions, as well as many functions only used while in a specific state, I realized that my component was getting to be well over a thousand lines of code and a bit unmanageable. To find the logic pertaining to the current section I was working on, I had to sift through hundreds of lines of code. I decided there had to be a better way… and there was!

I started by creating an AbstractActivityState that extended the State class. This had had any common properties and logic, as well as a bindable “Activity” object. This worked well for accessing the public variables of the activity. The problem came with private variables. While I would have had access to these if I had written all my logic within the Activity MXML, since I was passing the Activity object into my states, they were inaccessible.

There were three solutions I found for this problem:

  1. Make all the properties you need access to within the state public, and break encapsulation rules.
  2. Add additional Bindable properties to the the custom state classes and pass in the bindable private variables.
  3. Create a StateMiniModel that had all the bindable properties I needed and simply pass it to the custom state. This is handy if you don’t want to break encapsulation but have a great many common private variables to be passed to all your custom classes.

To make things even more simple, I added some listeners and protected ‘enter/exit’ classes to be called from within the AbstractActivityState so I when declaring my states in MXML I didn’t need to give it anything other than a name.

No Comments
23
Apr
2008

Facebook Friend Geocoder

I’m very excited about the MapQuest API and all the possibilities it offeres developers for creating mapping applications. I wanted to test the API and sharpen my own skills, so over the past few days I’ve been working on a Facebook geocoding application that will put any of your friends with current locations set on a Mapquest map.

It may be because I’m using a free developers license key, but I’ve noticed a few of the locations aren’t geocoding properly. For example, Roseville MN is turning up Roseville California.

I haven’t submitted the application to the Facebook library yet, but feel free to try it out and post any feedback you have either here or on the application about page.
**Update 10/24/2010: This is totally broken now **

4 Comments
13
Mar
2008

Speaking At FlashMN on Wednesday March 19

I will be speaking on developing MapQuest’s TripPix application (formerly MapMyPix) at the next FlashMN users group on Wednesday, March 19th. For those of you unfamiliar with the FlashMN users group, it meets at 7 on the third Wednesday of each month at Easel Training in Saint Paul.

The talk will include information on building application using the MapQuest Advantage API, AIR and Flex Builder 3.

No Comments
7
Aug
2007

"My God… Its full of stars!"


Have I mentioned how much I like the BitmapData class? Had a request pass by desk last week asking me to create a little app to be used in a presentation. They wanted it so that when a user clicked on a button in the middle, a star would fly across the screen to a random location, twinkling while it moved, then stay on the screen until the user clicked clear. They wanted somewhere between 30 and 100 stars on the screen.

While I think flash could have handled having that many MovieClips on screen pretty easily on its own, I wanted to see if I could make it more efficient. The solution I came up with was to use two BitmapData layers, one for moving the stars on the screen and creating the ‘twinkling trails’ and the other for housing all the stars in their final resting place.

The two layers of BitmapData (trailsCanvasBmp, and finalBallCanvasBmp) and a ParticleManager class to track the movement of the stars and slowly fades out the trailsCanvasBmp to give the twinkling effect while its moving. A star is created in the center of the screen, then shoots off to its random location. When the tween is complete the star is drawn to the top finalBallCanvasBmp class which is never cleared.

On each frame a random pixel is chosen from the finalBallCanvasBmp and if that pixel is NOT black (0×000000), then it attaches an mcTwinkle MovieClip which destroys itself upon finishing its animation.

The effect is really quite cool! You get the sense that each star is operating under its own principles, but its actually just two BitmapData objects interacting with the ParticleManager.

You will notice some major performance hits if you tell it to make too many stars at one time, or if the screen gets literally filled with stars, their may be more twinkling than your computer can handle. We’re on some beefy machines here at work, and I have had over 20,000 stars and haven’t noticed a performance hit. So your movies can truly be “Full of Stars”. ($1 to who ever can name the movie reference*)

There are a few other things going on here that I can elaborate on if requested. The background is generated using Perlin noise (so really there are 3 Bitmaps). Each star is colored using my Pallet class I can upload if desired. Full code for this project can be uploaded.

2 Comments