自定义控件系列 基于GraphicElement的动态背景"/>
flex4 自定义控件系列 基于GraphicElement的动态背景
效果图:
点击按钮可重新生成新的背景
单击单个元素可改变单个元素的外观
单个背景图案
package components
{
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.GraphicsPathCommand;
import flash.display.GraphicsPathWinding;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.utils.getQualifiedClassName;
import mx.utils.ColorUtil;
import spark.core.IGraphicElement;
import spark.primitives.supportClasses.GraphicElement;
public class FlowerGraphicElement extends GraphicElement
{
/**
* 绘图commands
* */
private var _commands:Vector.<int> = new Vector.<int>;
/**
* 绘图datas
* */
private var _datas:Vector.<Number> = new Vector.<Number>;
/**
* commands索引
* */
private var _ci:int;
/**
* datas索引
* */
private var _di:int;
/**
* 分度数
* */
private var _numOfLeaves:int = 5;
/**
* 图案的旋转度数
* */
private var _flowerRotation:Number = 0;
/**
* 线高的比例 子分级与分级
* */
private var _innerToOuterRadiusRatio:Number = 0.382;
/**
* 笔画重度 考虑到使用StrokedElement
* */
private var _strokeWeight:int = 1;
/**
* 图案颜色 考虑到使用FilledElement
* */
private var _color:uint = 0x808080;
/**
* 当前填充颜色 考虑到使用FilledElement
* */
private var _fillColor:uint = 0x808080;
/**
* 为演示目的 强制对象分享
* */
private var _shouldShareDisplayObject:Boolean;
public function FlowerGraphicElement()
{
super();
}
/**
* 设置分度数
* */
public function set numberOfLeaves(value:int):void
{
if ( value != _numOfLeaves )
{
_numOfLeaves = Math.max(3, value);
invalidateDisplayList();
}
}
public function get numberOfLeaves():int{ return _numOfLeaves; }
/**
* Ratio inner/outer radius 线高的比例
*/
public function get innerToOuterRadiusRatio():Number{return _innerToOuterRadiusRatio;}
public function set innerToOuterRadiusRatio(value:Number):void
{
if (_innerToOuterRadiusRatio != value)
{
_innerToOuterRadiusRatio = Math.max(0.1, Math.min(1, value));
invalidateDisplayList();
}
}
/**
* 笔画重度
*/
public function get strokeWeight():int{ return _strokeWeight;}
public function set strokeWeight(value:int):void{ _strokeWeight = value; }
/**
* 图案颜色
*/
public function get color():uint{return _color; }
public function set color(value:uint):void
{
if(_color != value)
{
_color = _fillColor = value;
invalidateDisplayList();
}
}
/**
* 图案的旋转弧度
* 首先是设置设置这个角度
* 用这个,当旋转图案时旋转属性不必受到影响
* 并且必须绘出
*/
public function set flowerRotation(value:Number):void
{
if ( value != _flowerRotation )
{
_flowerRotation = value;
invalidateDisplayList();
}
}
public function get flowerRotation():Number{ return _flowerRotation; }
/**
* 设置是否强制对象分析
* */
public function set shouldShareDisplayObject(value:Boolean):void
{
_shouldShareDisplayObject = value;
//通知主机此元素已更改且需要更新其图层的实用程序方法
invalidateDisplayObjectSharing();
}
public function get shouldShareDisplayObject():Boolean{ return _shouldShareDisplayObject; }
/**
* 确定此元素是否可以将它自己绘制到该序列的sharedDisplayObject
* */
public override function setSharedDisplayObject(sharedDisplayObject:DisplayObject):Boolean
{
return super.setSharedDisplayObject(sharedDisplayObject);
}
/**
* 如果元素需要一个独占的displayObject则为true
* */
protected override function get needsDisplayObject():Boolean
{
return !_shouldShareDisplayObject;
}
/**
* Flex调用 为graphic element 创建显示对象
* */
public override function createDisplayObject():DisplayObject
{
//父类将会创建InvalidatingSprite(继承自Sprite)
var displaySpirteObject:DisplayObject = super.createDisplayObject();
//根据需要个性化
setupDisplayObject(displaySpirteObject);
return displaySpirteObject;
}
private function setupDisplayObject(value:DisplayObject):void
{
if ( value is Sprite )
{
var sprite:Sprite = Sprite(value);
sprite.mouseEnabled = true;
sprite.mouseChildren = true;
sprite.addEventListener(MouseEvent.CLICK, clickHandler);
sprite.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
sprite.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
sprite.addEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
}
else
{
trace("不能设置显示对象:"+getQualifiedClassName(this));
}
}
/**
* 点击事件
* */
private function clickHandler(e:MouseEvent):void
{
//随机图案
innerToOuterRadiusRatio = Math.random();
numberOfLeaves = Math.random() * 10;
width = height = Math.random() * 150 + 50;
invalidateDisplayList();
}
/**
* 鼠标触摸事件
* */
private function rollOverHandler(e:MouseEvent):void
{
//将颜色向亮度亮的方向调整
_fillColor = ColorUtil.adjustBrightness(_color, 90);
invalidateDisplayList();
}
/**
* 鼠标移除事件
* */
private function rollOutHandler(e:MouseEvent):void
{
_fillColor = _color;
invalidateDisplayList();
}
/**
* 从场景中移除事件处理函数
* */
private function removeHandler(e:Event):void
{
var target:DisplayObject = DisplayObject(e.currentTarget);
target.removeEventListener(MouseEvent.CLICK, clickHandler);
target.removeEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
target.removeEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
target.removeEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
}
/**
* 是否可以与下一个IGraphicElement元素共享显示对象
* 覆盖强制取消共享显示对象
* */
public override function canShareWithNext(element:IGraphicElement):Boolean
{
return _shouldShareDisplayObject;
}
/**
* 是否可以与上一个IGraphicElement元素共享显示对象
* */
public override function canShareWithPrevious(element:IGraphicElement):Boolean
{
return _shouldShareDisplayObject;
}
/**
* 绘制元素和/或调整其内容的大小并定位该内容
* */
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
draw(unscaledWidth, unscaledHeight);
}
private function draw(w:Number, h:Number):void
{
//得到显示对象的画图工具
var graphic:Graphics = ( displayObject as Sprite ).graphics;
w = isNaN(w) ? this.width : w;
h = ( isNaN(h) ? this.height : h ) - 1;
/*
* 设置 graphic element 的根笛卡尔坐标 关联到绘图displayObject
* 用来绘图的关联到绘图displayObject的笛卡尔坐标可能不是从(0,0)而是从(drawX,drawY)开始
* graphical element 的笛卡尔坐标必须纳入计数器
* 因此displayObject显示对象必须是共享的
*/
var gx:Number = drawX + w/2;
var gy:Number = drawY + h/2;
//重设索引
_ci = 0;
_di = 0;
//为简单起见,1.65逼近,outerRadius关联cp,不会在外部边界,测量不准确
var outerRadius:Number = Math.min(w, h) / 1.65;
var innerRadius:Number = _innerToOuterRadiusRatio * outerRadius;
var cp:Point = new Point;
var ap:Point = new Point;
var r:Number = _flowerRotation;
var rMax:Number = r + 2 * Math.PI;
var angleStep:Number = Math.PI / _numOfLeaves;
//设置开始点
ap = Point.polar(innerRadius, r);
ap.offset(gx, gy);
_commands[_ci++] = GraphicsPathCommand.MOVE_TO;
_datas[_di++] = ap.x;
_datas[_di++] = ap.y;
while ( r < rMax )
{
//外部控制点
r += angleStep;
cp = Point.polar(outerRadius, r);
cp.offset(gx, gy);
//内部锚点
r += angleStep;
ap = Point.polar(innerRadius, r);
ap.offset(gx, gy);
//设置画曲线
_commands[_ci++] = GraphicsPathCommand.CURVE_TO;
_datas[_di++] = cp.x;
_datas[_di++] = cp.y;
_datas[_di++] = ap.x;
_datas[_di++] = ap.y;
}
//end point = start point
ap = Point.polar(innerRadius, r);
ap.offset(gx, gy);
_commands[_ci++] = GraphicsPathCommand.LINE_TO;
_datas[_di++] = ap.x;
_datas[_di++] = ap.y;
//重用前清除不必要的数据
//激活缓存工作 如果没有数据改变时data和command是不会被执行的
if ( _ci != _commands.length )
{
_commands.splice(_ci, _commands.length - _ci);
_datas.splice(_di, _datas.length - _di);
}
//考虑用到 FilledElement
graphic.beginFill(_fillColor, 1);
//绘制路径
graphic.drawPath(_commands, _datas, GraphicsPathWinding.NON_ZERO);
}
}
}
应用
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx=""
xmlns:s="library://ns.adobe/flex/spark"
xmlns:mx="library://ns.adobe/flex/mx"
minWidth="955"
minHeight="600"
creationComplete="application1_creationCompleteHandler(event)"
xmlns:ah="com.hulstkamp.sparkponents.*"
viewSourceURL="srcview/index.html">
<fx:Script>
<![CDATA[
import components.FlowerGraphicElement;
import mx.events.FlexEvent;
import mx.utils.ColorUtil;
//-------------------------------------------------------------------------
// Demo hacks
//-------------------------------------------------------------------------
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
buildField();
}
private function buildField():void
{
var colors:Array = [0x989508, 0xFFA800, 0xfd808e, 0xec656c, 0xbc0f3d, 0x19c6a2];
// addFlower(Math.random() * 75 + 50, 0, 0, colors[0], Math.random() * 10, Math.random());
// addFlower(Math.random() * 75 + 50, flowersGroup.width, 0, colors[0], Math.random() * 10, Math.random());
// addFlower(Math.random() * 75 + 50, flowersGroup.width, flowersGroup.height, colors[0], Math.random() * 10, Math.random());
// addFlower(Math.random() * 75 + 50, 0, flowersGroup.height, colors[0], Math.random() * 10, Math.random());
//occupy corners
addFlower(Math.random() * 75 + 50, 0, 0, colors[(i % colors.length)], Math.random() * 10, Math.random());
addFlower(Math.random() * 75 + 50, flowersGroup.width, 0, colors[(i % colors.length)], Math.random() * 10, Math.random());
addFlower(Math.random() * 75 + 50, flowersGroup.width, flowersGroup.height, colors[(i % colors.length)], Math.random() * 10, Math.random());
addFlower(Math.random() * 75 + 50, 0, flowersGroup.height, colors[(i % colors.length)], Math.random() * 10, Math.random());
//flower field
for (var i:int = 0; i < 37; i++)
{
addFlower(Math.random() * 100 + 100, Math.random() * flowersGroup.width, Math.random() * flowersGroup.height, colors[(i % colors.length)], Math.random() * 10, Math.random());
}
}
private function addFlower(size:Number, x:Number, y:Number, color:uint, numOfLeaves:int, ratio:Number):void
{
var ge:FlowerGraphicElement = new FlowerGraphicElement();
ge.shouldShareDisplayObject = false;
ge.width = ge.height = size;
ge.horizontalCenter = x - flowersGroup.width/2;
ge.verticalCenter = y - flowersGroup.height / 2;
ge.numberOfLeaves = numOfLeaves;
ge.innerToOuterRadiusRatio = ratio;
ge.color = ColorUtil.adjustBrightness(color, Math.random() * 64 - 32);
ge.blendMode = BlendMode.MULTIPLY;
flowersGroup.addElement(ge);
}
protected function button1_clickHandler(event:MouseEvent):void
{
flowersGroup.removeAllElements();
buildField();
}
]]>
</fx:Script>
<s:Group id="flowersGroup" width="600" height="600" horizontalCenter="0" verticalCenter="0" >
<s:mask>
<s:Group width="600" height="600">
<s:Rect width="100%" height="100%" radiusX="5" radiusY="5">
<s:fill>
<s:SolidColor color="0xff0000" />
</s:fill>
</s:Rect>
</s:Group>
</s:mask>
</s:Group>
<s:VGroup gap="7" horizontalCenter="0" verticalCenter="0" horizontalAlign="center">
<s:Label fontSize="14" color="0xffffff" text="基于GraphicElement的背景" />
<s:Label fontSize="11" color="0xffffff" text="点击一个元素改变其外观或按一下按钮" />
<s:Button label="重新生成" click="button1_clickHandler(event)" fontSize="11" chromeColor="0x80a000" />
<s:filters>
<s:DropShadowFilter distance="1" blurX="0" blurY="0" quality="0" />
</s:filters>
</s:VGroup>
</s:Application>
更多推荐
flex4 自定义控件系列 基于GraphicElement的动态背景
发布评论