您的位置:首页 > 其它

flash学习之 利用stage.invalidate()方法和render事件提高as3程序的运行效率

2011-03-21 11:50 796 查看
AS3中的DisplayObject有一个render事件,他会在重绘DisplayList之前触发,这给我们提供了在重绘之前最后一次操作的机会。

每次需要DisplayObject触发render事时,都要调用一次 stage.invalidate();

下面用一个小例子来说明一下具体用法把。

假设我们现在要写一个list组件,该组件有addItem()方法用于添加list项目,和remvoeItem(
)

方法用于删除list项目,当然还可能有addItemAt(
)
,
removeItemAt
(
)
等方法,这些方法调用后,都需要对list内的显示对象进行重新排列。

我们先实现一个List类,用于显示列表项目

List类中,有addItem(
)

和 removeItem(
)

这两个方法提供给外部调用,用于添加和删除list项目,这两个方法中除了将列表项目添加/
删除,还要调用一个方法来重新对list中的项目进行排列,layoutContents(
)


关键就是,这个layoutContents(
)
的调用,他的调用次数越少,那效率当然就越高啦,如果是常规的做法,就是类似这样:

代码:

public

function

addItem
(
item:
DisplayObject)
:
void

{

addChild(
item)
;

layoutContents(
)
;

}

将item加入后,重新排列列表

下面是List类的源代码:

代码:

package
{

import flash.
display.
DisplayObject;

import flash.
display.
Sprite;

import flash.
events.
Event;

public

class List
extends

Sprite

{

public

function

addItem
(
item:
DisplayObject)
:
void

{

addChild(
item)
;

layoutContents(
)
;

}

public

function

removeItem(
item:
DisplayObject)
:
void

{

if

(
contains(
item)
)

{

removeChild(
item)
;

layoutContents(
)
;

}

}

这个程序粗看似乎没什么问题,但却存在一个效率问题

如果只调用一次addItem,没问题,如果调用10次呢? 前9次的layoutcontents(
)
都不是必须的,只有第十次才是真正需要的这样程序的效率就降低了。

我们可以试一下

先需要一个简单的ListItem

代码:

package

{

import flash.
display.
Shape;

public

class ListItem
extends

Shape

{

public

function

ListItem(
)

{

super

(
)
;

graphics.
beginFill
(
0xFF6600)
;

graphics.
drawRect(
0,

0,

30,

16)
;

graphics.
endFill
(
)
;

}

}

}

然后测试

package
{

import flash.
display.
Sprite;

public

class ListTest
extends

Sprite
{

public

function

ListTest(
)

{

var

list
:
List
=

new

List(
)
;

addChild(
list
)
;

list
.
addItem
(
new

ListItem(
)
)
;

list
.
addItem
(
new

ListItem(
)
)
;

list
.
addItem
(
new

ListItem(
)
)
;

}

}

}

我们可以看到,输出了3次
do

layout 说明layoutcontents执行了3次,前两次都是多余的。

现在,解决办法就是利用render事件啦。

因为在当前帧内,显示列表更新前会触发render事件,所以在render事件触发后来排列列表项目,就可以保证排列方法在做了任意次的添加或删除操作后只需调用一次,从而提高效率。

这么做只需要对List类稍做一些改动,首先肯定是要监听render事件,我们可以仅监听stage对象的render事件即可,因为这样以后可以做一个独立的RepaintManger来管理所有组件的重绘(可以参考AsWing的RepaintManager类)。

在render事件触发后,做我们需要的调整,由于要render事件触发,就必须先调用stage.
invalidate(
)

,所以每次添加或删除list项目后,都要执行一次该方法,即:

代码:

public

function

addItem
(
item:
DisplayObject)
:
voide
{

.
.
.
.
.
.

stage.
invalidate(
)

}


于是监听的stage的render事件,所以在添加删除操作后,要做一个标记,表示list有改动,需要在render事件后重新排列,如果该标记为
false,那么即使render触发了也不做排列,因为stage的render事件也有可能是由于该stage内的其他child需要重绘而造成
stage的render触发。

下面是改过后的List代码

package
{

import flash.
display.
DisplayObject;

import flash.
display.
Sprite;

import flash.
events.
Event;

public

class List
extends

Sprite
{

private

var

changed:
Boolean

;

public

function

List(
)

{

super

(
)
;

addEventListener(
Event.
ADDED_TO_STAGE,

__addToStage)
;

}

public

function

addItem
(
item:
DisplayObject)
:
void

{

addChild(
item)
;

requireLayout(
)
;

}

public

function

removeItem(
item:
DisplayObject)
:
void

{

if

(
contains(
item)
)

{

removeChild(
item)
;

requireLayout(
)
;

}

}

private

function

requireLayout(
)
:
void

{

changed
=

true

;

if

(
stage
!
=

null

)

stage.
invalidate(
)
;

}

//对内部项目进行排列,可以是任意的排列算法

protected
function

layoutContents(
)
:
void

{

trace

(
"do layout"
)
;

var

y:
Number

=

0;

var

num:
int

=

numChildren;

for

(
var

i:
int
=
0;

inum;

i+
+
)

{

var

child:
DisplayObject
=

getChildAt(
i)
;

child.
x
=

0;

child.
y
=

y;

y
+
=

child.
height
+
2;

}

}

private

function

__addToStage(
e:
Event)
:
void

{

stage.
addEventListener(
Event.
RENDER,

__render)
;

if

(
changed)

stage.
invalidate(
)
;

}

private

function

__render(
e:
Event)
:
void

{

if

(
changed)

{

layoutContents(
)
;

changed
=

false

;

}

}

}

}

当我们再次运行ListTest的时候,do layout 只输出了一次。

就是这些内容,当然,你可能会说,需要做到这些根本不需要这么复杂,只要公开layoutContents方法,在所有操作调用之后让调用者自行调用一次layoutContents(
)


在这个例子中当然可以,但是当情况很复杂的时候,使用者每进行一次操作都要自行调用更新的方法,这样做并不是好的解决方案。试想,如果 flashplayer不会为我们处理显示DisplayObject的工作,而是每次addChild/
removeChild之后,我们都需要自行调用flashplayer底层的方法来让我们需要的东西显示出来,这样做显然很不好。

完了,就这些东东,写完之后俺感觉自己的表达能力不好,如果觉得我说的很模糊,那就研究下代码吧,全部代码都在上面了,欢迎指教和讨论
^
^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: