[TOC]
http://flex.apache.org/tourdeflex/index.html
**MXML**
MXML 是一种基于XML标签的标记语言,用于基于Flex的用户界面的组件和数据资产的布局和设计
**默认命名空间:**
fx-引用特殊语言声明性标签
s-引用Flex4框架中引入的spark组件库
mx-引用Flex3框架中引入的MXML组件库,在Flex4中仍然坚持
### MXML 语法
* * * * *
#### **设置组件属性**
MXML中组件属性使用的命名约定和对应的ActionScript属性相同。属性名以小写字母开头,大写字母区分属性名中的单词。
大多数组件属性设置和标签属性一样,形式如下:
~~~
<mx:Label width="50" height="25" text="Hello World"/>
所有组件属性可以设置为子标签,形式如下:
<mx:Label>
<mx:width>50</mx:width>
<mx:height>25</mx:height>
<mx:text>Hello World</mx:text>
</mx:Label>
~~~
使用常量设置属性
很多组件属性的有效值由静态常量定义,这些静态常量在ActionScript类中定义。MXML中可以使用静态常量设置属性值,也可以使用静态常量值,如下所示:
~~~
<!-- 使用静态常量设置属性。 -->
<mx:HBox width="200" horizontalScrollPolicy="{ScrollPolicy.OFF}">
...
</mx:HBox>
~~~
#### **在String值中包含换行符**
对于String类型的属性,有两种方式在String中插入换行符:
* 在MXML的String值中插入 代码
* 在ActionScript 用来初始化MXML 属性的String变量中插入“/n”
要使用&\#13;代码插入换行符,可以在MXML的属性值中包含该代码,如下所示:
`<mx:TextArea width="100%" text="Display Content"/>`
要使用ActionScript String变量插入换行符,可以创建一个ActionScript变量,然后使用数据绑定设置MXML中的属性,如下所示:
~~~
<mx:Script>
<![CDATA[
[Bindable]
public var myText:String = "Display" + "/n" + "Content";
]]>
</mx:Script>
<mx:TextArea width="100%" text="{myText}"/>
~~~
本例中,TextArea控件的text属性值被设置为包含一个换行符。
<font color="red">注意,本例中在属性定义前有[Bindable]元数据标签。</font>
元数据标签指定了myText属性可以作为数据绑定表达式的source。运行时当属性变化时数据绑定会自动将一个对象的source属性值复制给另一个对象的destination属性。
如果你省略了元数据标签,编译器会发出警告,指出该属性不能作为数据绑定的source。
#### **设置标量值数组**
当一个类以数组作为它的属性值时,可以在MXML中使用子标签表示该属性。下面例子中的组件有一个dataProvider属性,包含数字数组:
~~~
<mx:List width="150">
<mx:dataProvider>
<mx:Array>
<mx:Number>94062</mx:Number>
<mx:Number>14850</mx:Number>
<mx:Number>53402</mx:Number>
</mx:Array>
</mx:dataProvider>
</mx:List>
~~~
数组元素外的<mx:Array>和</mx:Array>标签可选。因此,这个例子代码也可以写成以下所示:
~~~
<mx:List width="150">
<mx:dataProvider>
<mx:Number>94062</mx:Number>
<mx:Number>14850</mx:Number>
<mx:Number>53402</mx:Number>
</mx:dataProvider>
</mx:List>
~~~
本例中,因为dataProvider属性的数据类型定义为数组,因此Flex会自动将三个数字定义转换为一个三元素数组。
#### **设置Object 属性**
当组件以对象作为属性值时,可以在MXML中用含标签属性的子标签表示该属性:
以下示例给出了一个ActionScript类,定义了一个含Address类型属性的PurchaseOrder组件:
~~~
import example.Address;
class PurchaseOrder {
public var shippingAddress:Address;
public var quantity:Number;
...
}
~~~
MXML中定义了PurchaseOrder组件,如下所示:(mynamespace 为自己的命名空间)
~~~
<mynamespace:PurchaseOrder quantity="3" xmlns:e="example">
<mynamespace:shippingAddress>
<mynamespace:Address name="Fred" street="123 Elm St."/>
</mynamespace:shippingAddress>
</mynamespace:PurchaseOrder>
~~~
#### **填充对象数组**
~~~
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<s:ArrayCollection id="sample">
<fx:Object label="Binding" cls="{BindingSample}"/>
<fx:Object label="Layout" cls="{LayoutSample}"/>
<fx:Object label="Binding" cls="{BindingSample}"/>
<fx:Object label="Layout" cls="{LayoutSample}"/>
<fx:Object label="Binding" cls="{BindingSample}"/>
<fx:Object label="Layout" cls="{LayoutSample}"/>
</s:ArrayCollection>
</fx:Declarations>
...
<s:ButtonBar width="100%" id="myButtonBar" change="indexChangeHandler(event)" dataProvider="{sample}"/>
~~~
效果图:

#### **在MXML中设置样式和效果属性**
MXML标签中的样式或效果属性和其他属性不同,因为它对应于ActionScript样式或效果,而不是ActionScript类的属性。
在ActionScript使用setStyle(stylename, value)方法设置这些属性,而不是object.property=value。
比如,在MXML设置fontFamily样式属性,如下所示:
~~~
<mx:TextArea id="myText" text="hello world" fontFamily="Tahoma"/>
~~~
该 MXML 代码等价于以下ActionScript 代码:
~~~
myText.setStyle("fontFamily", "Tahoma");
~~~
#### **在MXML 中设置事件属性**
MXML标签的事件属性允许你指定事件的事件监听器。该属性相当于在ActionScript中使用addEventListener()方法设置事件监听器。
比如,你可以在MXML中设置creationComplete事件属性,代码如下所示:
~~~
<mx:TextArea id="myText" creationComplete="creationCompleteHandler()"/>
~~~
该 MXML 代码等价于以下ActionScript 代码:
~~~
myText.addEventListener("creationComplete", creationCompleteHandler);
~~~
#### **编写ActionScript**
MXML文件经过编译最后也是被转换成AS来执行,在一个Flex程序中,主程序会被转换为Application对象的子类,自定义对象会被转换为父级对象的子类
在MXML中插入AS块
~~~
<mx:Script>
<![CDATA[
//这里是AS代码
]]>
</mx:Script>
~~~
此标签可以放在根节点内的任何位置,同时必须用CDATA将代码包起来。CDATA不能嵌套使用。
AS中的注释是 //单行注释
MXML中的注释和XML一样 <\!-- 注释-->
#### **举个栗子**
~~~
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx = http://www.adobe.com/2006/mxml fontSize="12">
<mx:Panel title="测试" width="400" height="200">
<mx:HBox width="300" height="150">
<mx:Button label="按钮" x="20" y="30"/>
<mx:Label text="文本"/>
</mx:HBox>
</mx:Panel>
</mx:Application>
~~~
<mx:Application>
这里的<mx:Application>是mxml的最外一层的标签做为根节点 根据xml的语法 需要一个命名空间“xmlns:mx”这就是一个命名空间
<mx:Panel>
这是面板组件 常用于其它组件的容器使用;使用title可以指定其标题名称
<mx:HBox>
这是一个矩形容器组件 注:在 mxml中容器和容器之间可以相互嵌套。
<mx:Button>
这是一按钮组件可以使用 label 指定其按钮名称
<mx:Label>
是一标签组件 可以使用 text指定其中的内容

* * * * *
### 数据绑定
将一个任意对象上所做的任何更新和修改,自动反映到另一个对象上
* 直接绑定
~~~
<s:Label text="添加绑定(合并字符串)"/>
<s:HGroup>
<s:TextInput id="myText03"/>
<s:Label text="+"/>
<s:TextInput id="myText04"/>
<s:Label text="="/>
<s:TextInput id="myText05" text="{myText03.text + myText04.text}"/>
</s:HGroup>
~~~
* 标签绑定
~~~
<s:Label text="绑定标签(相互绑定)"/>
<fx:Binding source="myText06.text" destination="myText07.text" twoWay="true"/> <!--双向绑定-->
<s:HGroup>
<s:TextInput id="myText06"/>
<s:Label text="="/>
<s:TextInput id="myText07"/>
</s:HGroup>
~~~
* AS变量绑定
~~~
<fx:Script>
<![CDATA[
[Bindable]
public var s:String = "";
]]>
</fx:Script>
<s:Label text="绑定AS变量"/>
<s:HGroup>
<s:TextInput id="myText08"/>
<s:Button label="update var" click="{s = myText08.text}"/>
<s:TextInput id="myText09" text="{s}"/>
</s:HGroup>
~~~
栗子:

### 布局
~~~
<s:BorderContainer id="container" width="100%" height="100%">
<s:layout>
<s:BasicLayout/> <!-- HorizontalLayout、VerticalLayout 、TileLayout -->
</s:layout>
<s:Label id="title" text="绝对布局"/>
<s:Button id="btn1" label="Button_01" width="300" mouseDown="{btn1.startDrag()}" mouseUp="{btn1.stopDrag()}"/>
<s:Button id="btn2" label="Button_02" width="300" mouseDown="{btn2.startDrag()}" mouseUp="{btn2.stopDrag()}"/>
<s:Button id="btn3" label="Button_03" width="300" mouseDown="{btn3.startDrag()}" mouseUp="{btn3.stopDrag()}"/>
</s:BorderContainer>
~~~
* BasicLayout(绝对布局)-- 手动定位坐标

* HorizontalLayout(水平布局)

* VerticalLayout(垂直布局)

* TileLayout(网格布局)

### 常用组件
* * * * *
# **Hello Again...**
* * * * *
### **视图状态(状态机)**
##### **什么是状态**
看起来是两个不同的页面,其实这是同一个自定义的组件。
它具有两种状态,Login状态和Register状态,状态不同,呈现出来的东西就不同。
 
##### **定义状态(写在<s:states />)**
~~~
<s:states>
<s:State name="default"/>
<s:State name="Register"/>
</s:states>
~~~
##### **改变状态**
UIComponent类定义了一个**currentState属性**,通过改变这个属性的值来更换状态。
这个属性的默认值是定义在需在<states></states>标签内的第一个状态.
<font color='red'>UIComponent 类是所有可视组件(交互式和非交互式)的基类。</font>
~~~
<s:Button id="b1" label="Change to State 1" click="currentState='State2';"/>
<s:Button id="b2" label="Change to the default" click="currentState='State1';"/>
~~~
##### **组件的状态**
通过点语法来设定一个组件属于某个状态的属性值
~~~
<s:Button id="loginButton" label="Login" label.Register="Register"/>
~~~
对于事件也一样可以用点语法,例如:
~~~
<s:Button id="b0" label="Default State" />
<s:Button id="b1" label="Click Me" click="b0.label='hello'" click.state_01="b0.label='goodbye'"/>
~~~
##### **添加或移除组件**
组件多了两个属性,includeIn和excludeFrom。
includeIn, 表示这个组件要被添加到属性值所指的状态,
excludeFrom,表示这个组件要从属性值所指的状态中删除,
includeIn和 excludeFrom不能在同一个组件标签里出现,他们的值可以是多个状态,之间用逗号隔开。
~~~
<s:states>
<s:State name="default"/>
<s:State name="state_01"/>
<s:State name="state_02"/>
<s:State name="state_03"/>
</s:states>
<s:CheckBox id="myCB" label="Checkbox" includeIn="state_01, state_03"/>
<s:TextArea text="Exclude from addTextInput" excludeFrom="state_02"/>
~~~
##### **更改一个组件的父元素**
~~~
<s:Panel id="Panel1" height="100" width="100" title="Panel 1">
<s:Button id="sonButton" includeIn="Parent1" label="son"/>
</s:Panel>
<s:Panel id="Panel2" height="100" width="100" title="Panel 2">
<fx:Reparent target="sonButton" includeIn="Parent2"/>
</s:Panel>
~~~
我们要换父亲的组件就是sonButton。
includeIn="Parent2"告诉我们了,在状态Parent2时,就要换了sonButton的父元素,换成fx:Reparent的父元素,即第二 个panel。
### **拖放**
##### **基本的拖放**
指定组件的mouseDown事件为 startDrag()方法
指定组件的mouseUp事件为 stopDrag()方法(否则组件会一直处于可拖放状态)
~~~
<s:Button id="btn01" label="这是一个按钮" mouseDown="{btn01.startDrag()}" mouseUp="{btn01.stopDrag()}"/>
<s:Image id="img01" x="300" source="temp.jpg" mouseDown="{img01.startDrag()}" mouseUp="{img01.stopDrag()}"/>
~~~
##### **列表类组件中拖放**
在列表类组件中拖放在,只需要将组件的dropEnabled,dragEnabled 属性都设为true就可以
dragMoveEnabled 属性 默认为false 表示拖动数据项时默认执行复制操作
~~~
<s:List id="selecte" height="100%" allowMultipleSelection="true" dropEnabled="true" dragEnabled="true" dragMoveEnabled="true"/>
<s:List id="draged" height="100%" dropEnabled="true" dragEnabled="true"/>
~~~
效果:

##### **在非列表类组件中拖放**
其一:需要将拖放的组件的mouseDown事件设置为初始化的 dragSource()函数;
~~~
protected function dragSource(event:MouseEvent):void
{
var dragInitiator:Button = Button(event.currentTarget);
var dragSource:DragSource = new DragSource();
var screenshot:BitmapData = new BitmapData(dragInitiator.width,dragInitiator.height);
screenshot.draw(this);
var proxy:Image = new Image();
proxy.source = new Bitmap(screenshot.clone()); // 演示如何抓取拖动组件的 “屏幕截图”
dragSource.addData({"x":event.localX,"y":event.localY},"button");
DragManager.doDrag(dragInitiator,dragSource,event,proxy); //proxy 是拖放代理 用来显示拖放状态的图片
}
~~~
其二:需要给放置的组件设置 dragEnter 事件,事件里判断是否接受拖动
~~~
protected function onEnter(event:DragEvent):void
{
if(event.dragSource.hasFormat("button"))
{
if(event.target is Panel)
DragManager.acceptDragDrop(Panel(event.target)); //接受拖动
else{
event.preventDefault(); //阻止使用默认的事件功能
}
}
}
~~~
其三:需要在放置的组件里设置放下的事件 dragEnter
~~~
protected function onDrop(event:DragEvent):void
{
var myData:Object = new Object();
myData = event.dragSource.dataForFormat("button");
btn.x = this.mouseX - myData.x;
btn.y = this.mouseY - myData.y; //设定组件的位置
}
~~~
效果:

~~~
~~~
### **动画**
##### **简单示范**
使用Animate来来创建和使用特效是很简答的:
* 首先要一个目标对象,以及这个对象的某些属性的名字,
* 这些属性会被Animate类修改来达到动画的效果。
* 还有些可选的参数,比如效果持续的时间。
* 一切都设置好后,调用play()来播放就是了
简单的例子:
我们给一个按钮应用了动画效果,动画的内容是把按钮向右移动100个像素。
~~~
<fx:Declarations>
<s:Animate id="mover" target="{button}">
<s:SimpleMotionPath property="x" valueFrom="0" valueTo="100"/>
</s:Animate>
</fx:Declarations>
<s:Button id="button" click="mover.play()"/>
~~~
我们还可以通过设置valueBy来设置移动的相对值。也可以只设置valueTo属性。当然出来的效果是不一样的。
如果你只设置了valueBy,那每次都是从当前位置再移动一段距离。
如果只设置了valueTo,那按第一次后,以后再按就没效果了
你可以在一个Animate里设置多个SimpleMotionPath来达到同时往不同方向移动的效果。比如下面这段代码:
~~~
<s:Animate id="mover" target="{button}" duration="1000">
<s:SimpleMotionPath property="x" valueFrom="0" valueTo="100"/>
<s:SimpleMotionPath property="y" valueTo="100"/>
<s:SimpleMotionPath property="width" valueBy="20"/>
</s:Animate>
~~~
##### **基本特效**
* 移动特效
就比如上面的例子可以用Move类来改写:
`<s:Move id="mover" target="{button}" xTo="100" yTo="200"/>`
* Resize特效
`<s:Resize id="resizer" widthTo="100" heightTo="50" target="{button}"/>`
* 变形特效:移动,旋转,伸缩
~~~
<s:Parallel id="transformer" target="{button}">
<s:Move xFrom="50" xTo="150" autoCenterTransform="true"/>
<s:Rotate angleFrom="0" angleTo="90" autoCenterTransform="true"/>
<s:Scale scaleXFrom="1" scaleXTo="2" autoCenterTransform="true"/>
</s:Parallel>
~~~
#### **项渲染器 itemRanderer**
##### **什么是项渲染器?**
指显示每一条数据时采用的形式
通过自定义的项渲染器,可以很方便的设置列表,表格的条目样式。
默认的List的渲染器:(类似label组件,只简单的显示一行文本)

##### **自定义项渲染器**
通过自定义,用户可以添加图片,按钮,选项框等等组件,来实现多样的功能。
通过传入复杂的数据,还可以完成复杂的数据显示。
下面就是一个自定义的例子:(包含原有的label,添加了复选框以及图片)
实现了一些小功能(左滑出现选项款,右滑出现删除等等)
~~~
<s:List id="myList" height="100%" itemRenderer="itemRanderer.render01"/>
...
myList.dataProvider = new ArrayCollection([
{label:"new message...0"},
{label:"new message...1"},
{label:"new message...2"}]};
...
<s:Group id="myGroup">
<s:CheckBox id="check" x="-50" y="{(height-check.height)/2}"/>
<s:Label id="lab" text="{data.label}" fontSize="24" y="{(height-lab.height)/2}"/>
<s:Image x="{width}" source="assert/delete.png"/>
</s:Group>
~~~

