正在加载...

转载请保留出处: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()
        {

        }

}
还没找到您要的东西?Google试试看吧,
Google更注重原创、时效性好的文章:


本文相关评论: 才 10 条评论
  1. yellow 2007-03-16 10:15:04

    apollo出来后,一个新的行业要出现了!

  2. aw 2007-03-16 10:22:02

    估计还有几天呢……

  3. ashun 2007-03-17 11:05:06

    你小子 半年不见 更加成熟了! 赞!

    等你回wh 找我喝酒!

  4. CG 2007-03-20 12:06:04

    这个类写得真棒,学习了

  5. aw 2007-03-20 10:21:07

    这个类后来又有改进。
    写的不是很好吧……稍后还会更新~

  6. aw 2007-03-20 10:29:33

    把两段函数合并作为MC的一个function了。
    本来想用一个static function作为MC的一个方法指向,但是发现不好弄。郁闷,写长了as1,换2真有点儿不习惯。不过我相信as2一定对理解as3有用,恩~

  7. Kakera 2007-03-25 06:28:00

    flex 已经实现了 padding 之类的属性, aw 看看他是怎么实现的..

  8. aw 2007-03-25 10:54:15

    Flex内建的类似Liquid的类吧。
    我这里只是简单讲一下原理吧,不过却是很好奇Flex内部怎么实现这玩意的~ 想学习一下原理code。
    因为很多时候用Flex开发实在是不合算,我觉得。

  9. amrabit 2007-04-19 10:14:25

    牛人讨论,本人只能看着喽!

  10. LIUHUAN 2007-05-18 08:56:12

    我也来发一个呵呵,

    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

[支持Ctrl+Enter]为了我们大家和家人的安全,留言请慎重!
声明:
1、本站仅与见过面的个人博客交换链接,见此文
2、留言时的头像是Gravatar提供的服务。如果您有兴趣并且有闲暇时间,可以看看这里的介绍