转载请保留出处:http://www.awflasher.com/blog/archives/822
在James O’Reilly出看到《Creating Liquid GUIs with Flash》一文,颇有感慨。其实很早我就考虑用Stage.onResize来实现动态布局的应用程序设计了,只不过一直没有系统地考虑过如何设计一些细节。James给出的类固然很强大,但是也觉得有点儿复杂,就简化了一下。
我把基本的功能封装成了一个“Liquid” 类,配以静态方法和静态属性,一来我觉得一个应用程序基本上都是在_root级进行模块划分,另一方面也算是为了和“Stage”类“遥相呼应”。再者,这里写的太复杂我想也会增加阅读的难度,毕竟我是想简述一个设计思想。最完美的解决方案我认为是模仿XHTML/CSS那样,任何MC都可以有自己的top、padding这种属性。但目前看来要用ActionScript写一套这个太麻烦了。等Apollo吧,反正快出来了。
OK,言归正传,首先简述一下Flash的内置类:Stage。Stage类有一些静态属性,其中最重要的就是align、scaleMode以及width和height,这四个属性配合onResize事件广播,就能完美地部署应用程序界面了。其原理就是,当swf在渲染层的尺寸改变的时候,Stage类会广播一个“onResize”事件,只要一个对象具有onResize方法,或者一个MovieClip具有onResize函数;更简单地,当前时间轴有一个函数onResize,这个方法、函数就会执行。而通过函数体中对Stage.width, Stage.height的引用,就能针对性地定位MovieClip了。值得一提的是,需要预先将align和scaleMode两个属性的值分别设置成“TL”和“noScale”后,应用程序就不会因为外界swf的拉伸而变形,而且基准中心永远在左上角,即左上角的坐标永远是(0,0),这对于我们定位其他资源是非常有意义的。
我将这些逻辑封装成Liquid类,来完成一些基本的设置。在时间轴上,调用一次Liquid的_init方法,让align和scaleMode预设置为以上提到的“TL”和“noScale”,然后将Stage的listner指向Liquid类的另一个静态方法onResize;另一方面,有addMC方法来保存所有需要绝对定位的MovieClip,开发者传入MovieClip的实例引用和一个绝对定位描述对象,并将这个描述对象最为这个MovieClip的一个实例属性,就能将这个“预定位置了的”MovieClip加入Liquid类的一个监听对象集合。
而在onResize中,去遍历这个集合,能得到MovieClip的实例指向和它的位置描述,这样每次外界舞台尺寸变化的时候,就可以重新按照预定的位置描述来分配位置了。
这里公布的Liquid类,只能算作抛砖引玉,可以针对诸如“边距”一类的属性(margin)再做一些扩展,当然,还是期待Apollo能轻松实现这些定位(基于CSS描述的MovieClip,不知道是不是YY了一点儿)。此外,Flex2是否有相应的package,由于我没有深入接触Flex,不得而知,如果有现有的package,拿过来直接用也不错。
Liquid类源码:
import utils.Delegate class utils.Liquid { public static function enterFullScreen():Void { Stage["displayState"] = "fullScreen"; } public static function exitFullScreen():Void { Stage["displayState"] = "normal"; } public static function noscale() { Stage.scaleMode = "noScale"; } public static function fullmode() { Stage.scaleMode = "showAll"; } private static var listeningObject:Object = new Object(); public static function addMC( _MC:MovieClip, _pos:Object) { _MC.__pos__ = _pos; if (_pos.marginLeft == undefined ) { _MC.__pos__.marginLeft = 0; } if (_pos.marginRight == undefined ) { _MC.__pos__.marginRight = 0; } listeningObject[_MC] = _MC; _MC.$applyLayout = function () { for (var _o in _pos) { var style:String = _o; var offset:Number = Number(_pos[_o]); switch (style) { case "left": this._x = offset + this.__pos__.marginLeft; break; case "right": this._x = Stage.width - offset - this._width - this.__pos__.marginRight; break; case "top": this._y = offset; break; case "bottom": this._y = Stage.height - offset - this._height; break; case "width": this._width = Stage.width * offset - this.__pos__.marginLeft - this.__pos__.marginRight; break; case "height": this._height = Stage.height * offset; break; default: break; } } } _MC.$applyLayout(); } public static function onResize() { for(var _m in listeningObject) { listeningObject[_m].$applyLayout(); } } static function _init() { Stage.align = "TL"; Stage.scaleMode = "noScale"; Stage.addListener(Liquid); } function Liquid() { } }
apollo出来后,一个新的行业要出现了!
估计还有几天呢……
你小子 半年不见 更加成熟了! 赞!
等你回wh 找我喝酒!
这个类写得真棒,学习了
这个类后来又有改进。
写的不是很好吧……稍后还会更新~
把两段函数合并作为MC的一个function了。
本来想用一个static function作为MC的一个方法指向,但是发现不好弄。郁闷,写长了as1,换2真有点儿不习惯。不过我相信as2一定对理解as3有用,恩~
flex 已经实现了 padding 之类的属性, aw 看看他是怎么实现的..
Flex内建的类似Liquid的类吧。
我这里只是简单讲一下原理吧,不过却是很好奇Flex内部怎么实现这玩意的~ 想学习一下原理code。
因为很多时候用Flex开发实在是不合算,我觉得。
牛人讨论,本人只能看着喽!
我也来发一个呵呵,
dynamic class com.StageManager {
var __items, __height, __width, __centerWidth, __centerHeight, __QWidth, __stageWidth, __stageHeight, __maxWidth, __minWidth, __maxHeight, __minHeight, __QHeight, __mode, __get__mode, __align, __get__align;
function StageManager() {
__items = new Array();
Stage.addListener(this);
this.onResize = function() {
this.setProps();
this.alignClips();
};
}
public function init(m, a, maxW, minW, maxH, minH) {
this.setMode(m || “noScale”);
this.setAlign(a || “TL”);
this.setHeight(maxH || 960, minH || 480);
this.setWidth(maxW || 1440, minW || 960);
}
public function alignClips() {
var i = 0;
while (i