把这个话题放在第一位,其实没有什么非凡的含义,只是我实在太恨button这东西了,恨不得多骂它两句。
从远古时代,这个所谓的button的东西就开始存在了。当时创建一个button要画上4帧,三个状态,还有一个点击的有效空间。后来知道了button其实只是一个MovieClip(MC),我就把button干脆换成一个两帧的MC,因为我不需要我的按钮那么生动活泼。不过每次都要在第一帧加个stop(),又要为每次按钮定义onRollOver和onRollOut事件,假如按钮有几十个,那都被烦死了。咳咳,先让我们来见识一下这个两帧的按钮。
(1)Ctrl+F8,新创建一个MC,名字就叫button_mc吧。
(2)MC简简单单,2个帧就行了。第一帧是按钮的初始状态,第二帧是鼠标划过的状态(如图)。
(3)好了,回到主影评,把button_mc拉到场景中,起名button_mc,在第一帧中插入代码:
==========================================================
button_mc.stop();
button_mc.onRollOver=function(){
gotoAndStop(2);
}
button_mc.onRollOut=button_mc.onReleaseOutside=function(){
gotoAndStop(1);
}
button_mc.onRelease=function(){
//your code
}
button_mc.onRollOver=function(){
gotoAndStop(2);
}
button_mc.onRollOut=button_mc.onReleaseOutside=function(){
gotoAndStop(1);
}
button_mc.onRelease=function(){
//your code
}
==========================================================
代码的含义我就不解释了,不清楚的请先了解ActionScript的基础。要注重的是
button_mc.onRollOut=button_mc.onReleaseOutside这一句,假如你不这样些,那么你在按钮上按住鼠标左键,然后在按钮外面释放,就不能回到初始状态了。
(4)测试影片,一个简单的按钮功能已经完成了:)
说了那么多废话,终于要进入今天的主题了!
怎样快速构建一个按钮然后只写onRelease就可以完成按钮的基本功能呢?
为了让我们不用重复些onRollOver和onRollOut事件,我们可以把这些事件集合到一起,成为一个抽象的按钮。看看我们怎么构建一个抽象的按钮吧:
新建一个as文件,命名为AbstractButton.as(随你喜欢),保存在命名空间com.netiod.example下。代码如下:
=========================================================
class com.netiod.example.AbstractButton extends MovieClip {
private var _enable:Boolean=true;
private function AbstractButton() {
this.onRollOver = this._rollover;
this.onRollOut = this.onReleaseOutside=this._rollout;
}
private function onLoad() {
this.stop();
}
public function toString():String {
return "[Object, SimpleButton]"+" name:"+this._name;
}
private function _rollover():Void {
if(!isEnable()) return;
this.gotoAndStop(2);
_extrollover();
}
private function _rollout():Void {
if(!isEnable()) return;
this.gotoAndStop(1);
_extrollout();
}
//here are the interface for the subclass to extand the events
public function _extrollover():Void{
}
public function _extrollout():Void{
}
//switch
public function enable():Void{
this._enable=true;
this.useHandCursor=true;
}
public function disable():Void{
this._enable=false;
this.useHandCursor=false;
}
private function isEnable():Boolean{
return this._enable;
}
}
private var _enable:Boolean=true;
private function AbstractButton() {
this.onRollOver = this._rollover;
this.onRollOut = this.onReleaseOutside=this._rollout;
}
private function onLoad() {
this.stop();
}
public function toString():String {
return "[Object, SimpleButton]"+" name:"+this._name;
}
private function _rollover():Void {
if(!isEnable()) return;
this.gotoAndStop(2);
_extrollover();
}
private function _rollout():Void {
if(!isEnable()) return;
this.gotoAndStop(1);
_extrollout();
}
//here are the interface for the subclass to extand the events
public function _extrollover():Void{
}
public function _extrollout():Void{
}
//switch
public function enable():Void{
this._enable=true;
this.useHandCursor=true;
}
public function disable():Void{
this._enable=false;
this.useHandCursor=false;
}
private function isEnable():Boolean{
return this._enable;
}
}
=========================================================
除了蓝色和红色的代码,其他基本上可以不去理会。可以看到,蓝色的代码正式实现了之前那个按钮的功能。而这段代码的精髓在于红色部分。_extrollover和_extrollout这两个函数,为按钮实现提供接口,使得onRollOver和onRollOut事件即使被复写(OverWrite,其实AS不提供规范的函数重载)也不会丢失变换状态功能。可能我的表达能力有限,这段描述有点难于理解。让我们看看一个真正的按钮是怎么实现的吧:
(1)按照第一个例子的1,2步创建button_mc。
(2)新建一个类型com.netiod.example.ImpButton(不再声明建类的过程)
代码如下:
=========================================================
class com.netiod.example.ImpButton extends com.netiod.example.AbstractButton {
private function ImpButton(){
_extrollover=moreOnRollOver;
_extrollout=moreOnRollOut;
}
private function moreOnRollOver():Void{
trace("onRollOver");
}
private function moreOnRollOut():Void{
trace("onRollOut");
}
private function moreOnRelease():Void{
//your code here
}
}
private function ImpButton(){
_extrollover=moreOnRollOver;
_extrollout=moreOnRollOut;
}
private function moreOnRollOver():Void{
trace("onRollOver");
}
private function moreOnRollOut():Void{
trace("onRollOut");
}
private function moreOnRelease():Void{
//your code here
}
}
=========================================================
*类的声明比较长,因为我没有设置classpath。
看红色代码,在这里实现了_extrollover和_extrollout函数并不会覆盖onRollOver和onRollOut事件。
(3)将com.netiod.example.ImpButton类注册到button_mc上去。
(4)把button_mc拉到场景上,测试影片。
怎样,将鼠标移到button_mc上去,button_mc能够转到第二帧同时又在输出面板能看到
"onRollOver"。没错,AbstractButton没有占用你的事件,但是可以让你快速创建一个按钮。
其实ImpButton的代码可以更少,甚至是一个空壳。当然,其实实践假如有共性,你也可以加
到AbstractButton上去,然后在提供修改接口。Enable和Disable也是非必要的,看你自己
的习惯。
"onRollOver"。没错,AbstractButton没有占用你的事件,但是可以让你快速创建一个按钮。
其实ImpButton的代码可以更少,甚至是一个空壳。当然,其实实践假如有共性,你也可以加
到AbstractButton上去,然后在提供修改接口。Enable和Disable也是非必要的,看你自己
的习惯。
由于是第一篇,所以语言组织得不是很好,希望你能看懂里面的奥妙,将它运用到其他地方去。
源文件:
很多传统的程序员刚接触Action Script的时候都应该是非常得心应手的。函数重载,这个概念对
他们来说应该已经根深蒂固了吧,不多当把函数重载的概念运用在Action Script上面的时候,就
会得到有趣的效果,先让我们看看一段程序吧:
他们来说应该已经根深蒂固了吧,不多当把函数重载的概念运用在Action Script上面的时候,就
会得到有趣的效果,先让我们看看一段程序吧:
function output(n:Number):Void{
trace("Output a number:"+n);
}
function output(str:String):Void{
trace("Output a string:"+str);
}
output(10);
//output("abc");
猜猜这段程序的输出结果是什么呢?很多人可能会回答“Output a number:10”,不过很可惜,输出的
结果是“Output a string:10”。这样还好,可能大家会猜测,Action Script并不支持函数重载,所以函
数output被重写了,运行的是第二个output函数。假如把程序改成这样呢:
function output(n:Number):Void{
trace("Output a number:"+n);
}
function output(str:String):Void{
trace("Output a string:"+str);
}
//output(10);
output("abc");
这回连编译都不给你通过了,这种感觉就像吃到一个苍蝇,到底是怎么回事呢?其实,AS是支持函数
重装的,而且还非常好用呢!不过不知道在Action Script3里面支不支持上述的函数重装。这里就稍微
谈论一下Action Script2.0的函数重载吧。
首先有一件东西要搞明白的,就是关于flash的arguments类,不过建议不要用类的定义来看待,把
它看成是每个函数都具有的一个变量。arguments[0]表示被访问的第一个参数,arguments[1]为第二
个,以此类推;arguments.length表示输入参数的个数;另外arguments还具有caller和callee变
量,比较少用,所以可以忽略。其次,需要弄懂typeof和instanceof,这两个要害词对大家应该不生疏
吧。对于原始类型,我们用typeof,对象便用instanceof。Flash中的typeof比较希奇,它返回原始
类型的名字,对应关系如下:
String |
|
影片剪辑 |
|
Button |
|
文本字段 |
|
Number |
|
Boolean |
|
Object |
|
Function |
|
把握了以上知识之后,我们就可以写出非常完美的函数重载了!先看看我们怎样重载文章开头的例子:
function output():Void{看看输出的结果,是不是令你非常满足呢?当然,重载也支持不同个数的输入变量,采用这种方式,
if(typeof(arguments[0])=="string"){
trace("Output a String:"+arguments[0]);
}else if(typeof(arguments[0])=="number"){
trace("Output a Number:"+arguments[0]);
}
}
output(10);
output("abc");
便可以随心所欲的写出自己的重装函数了。非凡在编写类型的构造函数时,这种方式更是显示出它的价值。
还没完呢。我有一次笔试的时候,有一道题叫我们用C语言写出printf函数的,那时我真的傻了,
我记得printf函数可以输入任意个数的参数,而我们完全没有学过怎样实现,难道像main函数中的
args[]数组,可是函数调用的时候输出的又不是数组...最后我还是放弃了。回去查看了printf函数
的源码,有点欲哭无泪...在这里我不想讲C语言是怎么实现的,我们看看我们伟大的AS是怎么实现的
吧。我们要写一个函数,它可以输入任意个数的Number,然后求出Number的最大值,假如参数中有
一个或者多于一个非Number的变量,则返回NaN。哦,再加上一个条件吧,代码不能超过5行!
好吧,看看一个比较傻的实现方式:
function max():Number{
for(var i:Number=0,m:Number=Number.NEGATIVE_INFINITY;i<arguments.length && typeof("number"==arguments[i]);m=Math.max(m,argument[i]),i++){;}
return m;
}
trace(max(1,2,5,93,5615454,999,-451));
看看结果,还满足吧?其实它连5行都没有。有人会说,那个m不是临时变量吗?在for外面不就没有
了吗?在其他地方是,在ActionScript中就偏偏不是!好啦,我也不说太多了,希望能够抛砖引玉,
arguments实在太强大了!