Complex / Irregular Shaped Flex UIComponent

Complex / Irregular Shaped Flex UIComponent

So I needed to lay a complex shaped graphic over the right edge of toggleButtonBar menu in one of my Flex projects. The problem was that I need to be able to click the menu under the transparent parts of the graphic.  I don’t know if there’s a secret mx:Image attribute that allows for it but I couldn’t get it to work. I also had to make this compatible with Flash Player 9 and Flex 3 so FXG was out of the question and bringing in the Degrafa library was a bit too heavy for just this one task.

One solution is creating a “Shape” object and passing the graphic at hand to the beginBitmapFill method.  The problem with this is that if you need to use constraints like “horizontalCenter” to align it, you’re out of luck as that’s only available with subclasses of the UIComponent which the Shape class is not.

If you need constraint layout capabilities, just use UIComponent instead of Shape.  I also found a lot of examples using the “Loader’ class to get the bitMapData of the image. In the example below, you’ll see a different way to do this with an embedded image. Here’s the image that I was working with and sample code with a button to test:

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" layout="absolute" creationComplete="init()">
 
	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.core.UIComponent;
 
			[Embed(source="curtain.png")]
			private var curt:Class;
			private var curtBitmapData:BitmapData = new curt().bitmapData;
 
			public function init():void{
 
				var curt:UIComponent = new UIComponent();
				curt.graphics.beginBitmapFill(curtBitmapData);
				curt.graphics.moveTo(82,0);
				curt.graphics.lineTo(100,50);
				curt.graphics.lineTo(95,81);
				curt.graphics.lineTo(52,366);
				curt.graphics.lineTo(12,530);
				curt.graphics.lineTo(0,672);
				curt.graphics.lineTo(222,672);
				curt.graphics.lineTo(222,0);
				curt.graphics.lineTo(82,0);
				curt.setStyle("horizontalCenter", -100);
				curt.y = 60;
				this.addChild(curt);
			}
 
			public function clickMe():void{
				Alert.show("Hit Test");
			}
 
		]]>
	</mx:Script>
 
	<mx:Button horizontalCenter="0" y="216" label="Button" click="clickMe()" width="532"/>
 
</mx:Application>

Instead of blindly figuring out the coordinates, I created a crude app to help me out. I figured I could get away with just using straight lines and not the “Graphics.curveTo” method. Here it is:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="1024" minHeight="768" creationComplete="init()" backgroundColor="#FFFFFF">
	<mx:Script>
		<![CDATA[
 
 
			[Bindable]
			public var gX:Number;
 
			[Bindable]
			public var gY:Number;
 
			[Bindable]
			public var lX:Number;
 
			[Bindable]
			public var lY:Number;
 
			public function init():void{
				this.curtain.addEventListener(MouseEvent.CLICK, mouseClick);
				this.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveGlobal)
				this.curtain.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveLocal)
			}
 
			public function mouseMoveGlobal(e:MouseEvent):void{
				gX = e.stageX; 
				gY = e.stageY;
			}
 
			public function mouseMoveLocal(e:MouseEvent):void{
				lX = e.localX;
				lY = e.localY;
			}
 
			public function mouseClick(e:MouseEvent):void{
				svgLog.text += "curt.graphics.lineTo(" + lX + "," + lY + ");\n";
			}
 
		]]>
	</mx:Script>
	<mx:Image x="385" y="37" source="curtain.png" id="curtain" alpha="1.0"/>
	<mx:Label x="10" y="10" text="Global x: {gX}" id="globalX"/>
	<mx:Label x="10" y="30" text="Global y: {gY}" id="globalY"/>
	<mx:Label x="120" y="10" text="Local x: {lX}" id="localX"/>
	<mx:Label x="120" y="30" text="Local y: {lY}" id="localY"/>
	<mx:TextArea x="10" y="67" height="504" width="247" id="svgLog"/>
 
</mx:Application>

All in all, this works and it was quick. If anyone has any other ideas on how to go about achieving this, I’d love to here it!