Custom Circle Layout for Flex Spark Components
If any of you have tried to make custom layouts in Flex 3.0 or earlier, then the new graphics code is going to be a breath of fresh air.
The basis of it is to start by writing your custom layout component as follows:
package joc
{
import spark.components.supportClasses.GroupBase;
import spark.layouts.supportClasses.LayoutBase;
import spark.primitives.supportClasses.GraphicElement;
public class CircleLayout extends LayoutBase {
public const CIRCLE:Number = Math.PI * 2.0;
private var _startRot:Number = 0.0;
public function set startRotation( rot:Number ):void {
_startRot = rot * CIRCLE;
target.invalidateDisplayList(); // notify the target container that the layout has changed
}
public function CircleLayout()
{
super();
}
public override function updateDisplayList( width:Number, height:Number):void {
var numItems:int = target.numElements;
var cx:Number = width/2.0;
var cy:Number = height/2.0;
var scale:Number = ((width+height)/2.0)/640;
for(var i:int = 0; i
var item:GraphicElement = target.getElementAt(i) as GraphicElement;
var angle:Number = _startRot + ((CIRCLE / numItems)*i);
var nx:Number = (Math.cos( angle ) * (width/2.5) ) + cx;
var ny:Number = (Math.sin( angle ) * (height/2.5) ) + cy;
item.setLayoutBoundsPosition(nx-50, ny-50 );
item.width = 100 * scale;
item.height = 100 * scale;
}
}
The updateDisplayList method is where the code handles repositioning and sizing of added Elements. My code works by taking each Element one at a time and positioning them around the circumference of a circle. The one slight enhancement that I have included is the 'startRotation' setter which changes the angle at which layout starts and then tells the Component which this layout is placed on to recalculate it Display List.
Example Code:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
creationComplete="Setup()"
xmlns:joc="joc.*">
<fx:Script>
<![CDATA[
import spark.primitives.Ellipse;
import mx.graphics.SolidColor;
private const NUM:int = 7;
private function Setup():void {
for(var i:int = 0;i < NUM; i++) {
addCircle();
}
private function addCircle():void {
var e:Ellipse = new Ellipse();
e.width = 100;
e.height = 100;
var c:int = Math.random() * 0xFFFFFF;
e.fill = new SolidColor(0xFF0000 | c);
circles.addElement( e );
}
protected function button1_clickHandler(event:MouseEvent):void
{
addCircle();
}
]]>
</fx:Script>
<s:Group id="circles" width="100%" height="100%">
<s:layout>
<joc:CircleLayout startRotation="{startRot.value}" />
</s:layout>
</s:Group>
<s:Button label="Add Circle"
click="button1_clickHandler(event)" />
<s:HSlider id="startRot"
width="100%"
minimum="0.0" maximum="1.0"
stepSize="0.001" valueInterval="0.001"
liveDragging="true"
/>
</mx:VBox>
Although some of this code may be unfamiliar to Flex 3.0 users, the layout is simply placed within any 'group' of components to start using it. Here you can see my CircleLayout used in a group tag. Then the 'Setup' method is called to 'Ellipses' (also a new tag) and the layout is invoked as needed by the Framework. LiveDragging is enabled on the Slider to allow you to interactively change the start angle from which the Layout calculates places around the ellipse.
p.s. please let me know if the layout of this post has any problems in your browser as the blogging software was fighting me over inserting code samples.
