您的位置:首页 > 其它

自定义组件开发 第二节 MXML组件开发

2011-04-07 10:11 316 查看
自定义组件开发第二节MXML组件开发
本节,我们以“自定义播放器”为实例,来学习MXML组件开发的方法。

学习目标

1.了解MXML组件开发的特点。

2.学习使用MXML语言开发组件,逻辑部分要结合ActionScript语言。

3.开发组件“自定义播放器”。

MXML组件开发的特点

为什么要开发组件?简而言之,是因为组件有利于代码的维护和复用。组件可以被定义在MXML文件(以.mxml为后缀的文件)或者ActionScript文件(以.as为后缀的文件)中。因此,有两种组件开发的形式:MXML组件开发及ActionScript组件开发。凡是定义在MXML文件中的组件都可以转化为定义在ActionScript文件中的组件。FlexSDK中的大部分组件都是定义在ActionScript文件中的。

然而,MXML组件开发也有其适用之处。MXML组件比较适合“组合模式”的组件,通过MXML,可以很方便的进行子组件的布局及数据绑定。以下是一些MXML组件开发的示例,更多的内容还需读者在实践中体会摸索。

MXML组件开发的优点:

可以利用“设计”模式,进行所见即所得的界面开发。
可以快速的添加子组件。不需要申明一个实例,然后再调用addChild(),将其添加到父组件的布局中去。
可以很方便地进行数据绑定。使用“{binding_expression}”可以快速将任意可绑定的数据源绑定到指定位置。
可以很方便的定义类实例,不需要显示的初始化。例如定义<fx:Binding/>后,应用程序运行时会自动初始化该实例。

MXML语言的缺点:

没有ActionScript的辅助,无法完成复杂的逻辑。
MXML组件默认都是public的,没有访问限制。
MXML标签中定义的事件是不可以被移除的。如<mx:Buttonclick="doClick()"/>,click事件是不可以被移除的。
不能自定义构造函数。

使用FlashBuilder4和MXML语言开发组件的步骤:

新建Flex库项目。Flex库项目编译后可以产生swc文件,可以作为组件发布的主要形式。
新建MXML组件文件,文件名即为组件名。
继承现有组件。文件内部第一级标签即为所继承组件名。
在MXML文件主标签里加implements属性可以继承接口。
在MXML文件里添加各种标签,包括可视组件,数据服务,验证,特效等。如果是非可视的标签,如特效等要加到<fx:Declarations>标签里,这是Flex4的新特点。
可以在<fx:Script>标签里添加ActionScript代码,以实现逻辑,比如事件处理等。代码要被<![CDATA[和]]>包围。
可以在<fx:Style>标签里添加CSS样式代码,以设置组件样式。
可以添加<fx:XML>、<fx:XMLList>、<fx:Array>、<fx:Model>等实用标签,以提供更好的功能。这些标签都要加在<fx:Declarations>标签里。

开发实例

本节通过开发一个“自定义播放器”组件,来讲解MXML组件开发技术。界面布局、组件使用等部分采用MXML语言,逻辑部分采用ActionScript语言。因为是组合式组件,不涉及组件生命周期等,所以可以利用MXML来开发,方便布局和属性设置等。

先看一下最终使用效果图:(图五十九)

图五十九

播放器预览



上部即是我们要做的“自定义播放器”组件,中间和下部是文字介绍和播放列表,不属于“自定义播放器”组件。

接下来,和我一起一步一步开发“自定义播放器”。

1.设计“自定义播放器”组件功能

播放器是一种很常用的组件,既可以是一个独立产品,也可以集成到大系统中,如教学系统、会议系统、娱乐网站等,主要分为音频播放器和视频播放器。

对于视频播放器,Flex3框架的mx.controls.VideoDisplay类提供了视频播放的视频显示和基本控制,但是没有提供控制界面等播放器必需的元素。Flex4框架保留了此类,但是在新增的spark组件体系中,有功能更加完善的视频播放器支持类。spark.primitives.VideoElement类提供了基本控制和显示功能,但是没有外壳,spark.components.VideoPlayer类是带完整外壳的视频播放器组件,spark.skins.default.VideoPlayerSkin是spark.components.VideoPlayer类的默认皮肤,还有支持组件:VideoPlayerScrubBar(时间条),VideoPlayerVolumeBar(音量条),VideoPlayerVolumeBarMuteButton(静音按钮)。可以说功能非常完善了。

对于音频播放器,Flex4框架还没有提供现成的完整组件,但是flash.media包提供了对声音的基本控制。互联网上有封装好的开源音频播放器类库,接口类似于Flex视频播放器,可以拿来复用。地址为:http://rojored.com/#simple-flex-audio-player。

我们的“自定义播放器”就是要结合视频播放器和音频播放器的功能,可以同时播放视频和音频,自动切换显示区的有无。

详细功能列表:

1.可以加载视频和音频文件,自动判断并播放。

2.如果是视频,则有显示区,是音频,则无显示区。

3.播放/暂停按钮,具有播放/暂停控制功能;停止按钮,具有停止并返回开头控制功能。

4.时间条,可以显示播放进度;拖动控制播放进度。

5.已播放时间、总时间显示。

6.音量条,可以控制声音大小。切换视频和音频,音量不变。

7.静音按钮,可以切换静音。静音时,音量条可以调节,可以设置音量,以便在不静音时生效。

8.信息,可以显示播放内容的额外信息,如内容描述。

9.播放视频时,单击显示区切换视频播放和暂停状态。

2.新建“自定义播放器”组件库项目及文件、示例项目及文件

a.新建Flex库项目,项目名:CustomPlayer。其它选项默认即可。构建后,FlashBuilder4会自动在bin文件夹中生成swc文件,即编译打包的组件。

b.在src文件夹中新建包,名称:cn.airia.fb4.customPlayer。FlashBuilder4会自动创建相应文件夹。

c.在包cn.airia.fb4.customPlayer中新建MXML组件CustomPlayer,继承自spark.components.Group。宽度100%,高度不填,布局改为spark.layouts.VerticalLayout。

d.新建Flex项目,项目名:CustomPlayerSample,作为示例项目,默认新建CustomPlayer.mxml文件作为主应用程序文件。示例项目需要使用组件,有多种方法,我们采用这种方法:“库路径”>“添加项目”>“CustomPlayer”。在发布时,可以将最终CustomPlayer组件的swc文件复制到CustomPlayerSample项目的libs文件夹中,并从库路径中删除CustomPlayer项目,这样就可以独立运行CustomPlayerSample了。

e.在CustomPlayerSample项目的“属性”>“项目引用”里添加对CustomPlayer项目的引用。在某些时候有用,比如打开CustomPlayerSample项目时也打开CustomPlayer项目。

3.编写示例程序类CustomPlayerSample

示例程序用来使用和测试“自定义播放器”组件。可以简单处理,这里不详解了。

设计界面如下:(图六十)

图六十

播放器设计界面



上部是“自定义播放器”组件。各位读者因为还没编好“自定义播放器”,所以只会显示空白,没有播放控件。中间是一段介绍文字。下部是播放列表,一个List,选择项目后,“自定义播放器”会播放相应视音频。

我把示例程序CustomPlayerSample的主题设为了Wireframe,如果主题不同,组件在示例程序中的表现也不同,但是组件本身是一样的。

代码如下:

<?xmlversion="1.0"encoding="utf-8"?>
<s:Applicationxmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:customPlayer="cn.airia.fb4.customPlayer.*"
minWidth="800"
minHeight="600"
viewSourceURL="srcview/index.html">
<!--这是Flex4的新布局组件-->
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
importmx.collections.ArrayCollection;
//播放列表数据,可绑定
[Bindable]
privatevarplayListDP:ArrayCollection=newArrayCollection([
{label:"10秒钟的视频",url:"videos/10秒.flv"},
{label:"黑猩猩打空手道",url:"videos/空手道.flv"},
{label:"电话来了铃声",url:"audios/dddd.mp3"}]);
/**
*给播放器要播放文件的源路径和额外信息,播放
*/
privatefunctionplay(event:Event):void{
varitem:Object=(event.targetasList).selectedItem;
player.source=item.url;
player.info=item.label;
player.play();
}
]]>
</fx:Script>
<!--这就是我们要编写的“自定义播放器”组件-->
<customPlayer:CustomPlayerid="player"
horizontalCenter="0"
width="450"
bottom="250"
top="20">
</customPlayer:CustomPlayer>
<!--文字介绍-->
<mx:Texty="360"
width="450"
horizontalCenter="0"
color="#EA9FA4"
text="上面是一个简单的“自定义播放器”组件,可用于会议系统、教学系统、娱乐系统等。选择播放下面列表里的视频或音频:"/>
<!--播放列表,选择项目后播放对应视音频-->
<s:Listid="playList"
dataProvider="{playListDP}"
labelField="label"
y="400"
width="450"
height="100"
horizontalCenter="0"
selectionChanged="play(event);"/>

</s:Application>

4.编写组件类CustomPlayer

CustomPlayer组合了官方视频类——VideoElement类,以及开源音频类——rojored的Audio类,并加上统一的控件控制两者,和额外的功能、改进,如点击视频切换播放暂停,静音后还能设置音量值等。

具体讲解可以参见代码注释,结合代码讲解更加直观,易于理解。

设计界面如下:

图六十一

CustomPlayer



在播放视频时会自动显示视频显示区。

代码如下:(代码片段包含了本例讲解、注释)

<?xmlversion="1.0"encoding="utf-8"?>
<!--这是Flex4的新容器组件,没有皮肤,性能更好-->
<s:Groupxmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:rojored="com.rojored.view.controls.*"
width="100%"
creationComplete="init();">
<!--这是Flex4的新布局组件,这里采用垂直布局-->
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
/**
*标示播放类型的常量
*/
publicstaticconstVIDEO:String="video";
publicstaticconstAUDIO:String="audio";
/**
*设置的音量
*不等同于播放对象的音量,在静音时不为0,仍然保持设置值
*/
[Bindable]
privatevarvolume:Number;
/**
*播放对象
*可选VideoElement和Audio两种类
*但是调用的接口方法类似,所以不限定类型
*/
[Bindable]
privatevarplayObject:*;
/**
*源属性
*直接和播放对象的源挂钩
*/
[Bindable]
publicfunctiongetsource():Object{
returnplayObject.source;
}
publicfunctionsetsource(value:Object):void{
//设置源后,要设置播放对象,以便选择播放视频或音频
setPlayable(value);
}
/**
*显示在控制栏的额外信息
*/
privatevar_info:String;
[Bindable]
publicfunctiongetinfo():String{
return_info;
}
publicfunctionsetinfo(value:String):void{
_info=value;
}
/**
*初始化
*默认播放是视频,音量值0.7
*/
privatefunctioninit():void{
playObject=video;
volume=0.7;
}
/**
*播放
*因为视音频播放对象播放方法一样,所以可以不用判断类型
*/
publicfunctionplay():void{
playObject.play();
}
/**
*暂停
*因为视音频播放对象暂停方法一样,所以可以不用判断类型
*/
publicfunctionpause():void{
playObject.pause();
}
/**
*切换播放和暂停状态
*如果已播放,则暂停,如果已暂停,则播放
*/
publicfunctiontogglePlayPause():void{
playObject.playing?pause():play();
}
/**
*停止
*因为视音频播放对象停止方法一样,所以可以不用判断类型
*/
publicfunctionstop():void{
playObject.stop();
}
/**
*根据源来设置播放对象
*先判断类型,然后停止非此类型的播放器,切换到此类型的播放器
*如果是视频类型,显示视频容器,如果是音频类型,隐藏视频容器
*/
privatefunctionsetPlayable(source:Object):void{
switch(judgeType(source)){
caseVIDEO:
audio.source=null;
audio.stop();
//显示视频容器
videoContainer.visible=true;
//标记显示列表失效,这样程序会自动更新绘制显示列表,否则视频位置和大小会有问题
videoContainer.invalidateDisplayList();
playObject=video;
playObject.source=source;
break;
caseAUDIO:
video.source=null;
video.stop();
//隐藏视频容器
videoContainer.visible=false;
playObject=audio;
playObject.source=source;
break;
}
}
/**
*判断播放类型
*利用正则表达式判断文件名后缀,如果是.flv,则为视频,是.mp3,则为音频
*还可以添加其它文件类型的判断,现在暂时不考虑
*/
privatefunctionjudgeType(source:Object):String{
if(newRegExp("(\.flv)$","i").test(source.toString())){
returnVIDEO;
}elseif(newRegExp("(\.mp3)$","i").test(source.toString())){
returnAUDIO;
}
returnnull;
}
/**
*格式化时间
*将
*VideoElement返回的是秒,Audio返回的是毫秒,要处理好
*/
privatefunctionformat(value:Number):String{
varseconds:Number;
if(playObjectisAudio){
seconds=Math.floor(value/1000);
}elseif(playObjectisVideoElement){
seconds=value;
}
varresult:String=Math.floor(seconds%60).toString();
//如果是秒数是1位数,则在前面添加1个0
if(result.length==1){
result=Math.floor(seconds/60).toString()+":0"+result;
}else{
result=Math.floor(seconds/60).toString()+":"+result;
}
returnresult;
}
]]>
</fx:Script>
<!--将播放对象的音量绑定为设置音量,如果静音了,则为0-->
<fx:Bindingdestination="video.volume"
source="muteBtn.selected?0:volume"/>
<fx:Bindingdestination="audio.volume"
source="muteBtn.selected?0:volume"/>
<!--音频播放对象,因为是非可视对象,所以要放在<fx:Declarations>标签内-->
<fx:Declarations>
<rojored:Audioid="audio"/>
</fx:Declarations>
<!--视频播放对象,因为VideoElement不能接受click事件,所以用一个Group包装-->
<s:Groupid="videoContainer"
click="togglePlayPause();"
width="100%"
height="100%">
<s:VideoElementid="video"
width="100%"
height="100%"
autoRewind="true"/>
<!--停止后自动回复到开头-->
</s:Group>
<!--播放时间条,将值和播放对象的播放头时间双向绑定,这样就可以同步了-->
<!--这里不采用s:HSlider组件,否则value的双向绑定会导致播放问题-->
<mx:HSliderid="timeSlider"
width="100%"
minimum="0"
maximum="{playObject.totalTime}"
value="@{playObject.playheadTime}"
liveDragging="false"/>
<s:Groupwidth="100%">
<!--播放暂停按钮,采用切换按钮,切换播放和暂停-->
<s:ToggleButtonid="playPauseBtn"
label="{playObject.playing?'暂停':'播放'}"
width="54"
x="0"
selected="{playObject.playing}"
click="togglePlayPause();"/>
<!--停止按钮,停止播放-->
<s:Buttonid="stopBtn"
label="停止"
click="stop();"
x="60"
width="52"/>
<!--播放时间显示,包括当前播放头时间和总时间-->
<mx:Labelid="time"
x="119"
width="76"
text="{format(playObject.playheadTime)}/{format(playObject.totalTime)}"/>
<!--静音按钮,采用切换按钮,切换后会自动影响绑定它的播放对象音量值-->
<s:ToggleButtonid="muteBtn"
label="静"
width="33"
x="218"/>
<!--音量条,将值和设置的音量值双向绑定,而非播放对象的当前音量,因此不受静音影响-->
<!--因为valueInterval默认为1,不合要求,要改为0,也就是无值间隔-->
<s:HSliderid="volumeSlider"
width="86"
x="252"
y="5"
minimum="0"
maximum="1"
valueInterval="0"
value="@{volume}"
liveDragging="true"/>
<!--信息标签,显示赋给的额外信息-->
<mx:Labelid="infoLabel"
text="{info}"
x="346"
width="104"/>
</s:Group>

</s:Group>

总结:

本节使用了官方组件和开源类库自定义播放器组件,满足自己的特殊需要。比如可以同时播放视频和音频、点击视频能暂停等。MXML组件开发利用MXML做界面布局,ActionScript做逻辑运算,各得其所,方便高效。

开发时,经常要自定义组件,这时可以充分利用已有的组件,减少重复开发带来的浪费。所以,要多多关注全世界的类库,同时,也可以把自己的成果贡献给世界。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: