AlternativaGUI研究
真的是非常非常久没有写博客了,工作后好像没有学生时代那么热衷于代码的优雅,总想着快点搞完回家睡大觉。。
看来确实应该改变下生活态度!故今日深夜更新一篇博文。
前些天,应该是几个月之前,当时打算写一套GUI来满足播放器的界面需求,那时候心血来潮把那套GUI取名为FdUI,后来难产死掉了,原因一来是把功能想得太牛逼,打算XML控制布局 + 类CSS语法的皮肤 + 皮肤资源自动加载,二来时间不够,老板项目催得紧UI的bug还一大堆没人修,火一大没把持住,一夜回到解放前,把代码全给删了。
代码删了日子还得过,项目还得做,FdUI没了还会有FeUI冒出来,项目紧就暂时从网上找个UI库用着吧。
Flex是提供组件的,可那是屎,坚决不用!
Aswing这个UI库确实不错,功能强大。但是doc一打开满屏的api。。Java学得太多反忽略了脚本语言的灵活性,太重,大部分功能我用不到!测试下来觉得响应有些慢,里面函数调函数太多层的缘故吧。
之外还有一些做demo的组件功能又太弱,比如bit101的MinimalComps。。。还有李志大大的miniUI。话说李志大大牛逼啊,are2d这个东西可以去搜下,我因为时间管理不善stage3D的研究没能坚持下来,也觉得有些可惜。
最后登场的,也就是我后来采用的UI库(我真是老套。。。)就是标题中的AlternativaGUI!!!
Alternativa出牛逼的3D引擎,但是去过官网的同学就知道Alternativa3D的下面还有个硕大的AlternativaGUI,这玩意儿不开源,但免费。而且这个UI库一个有意思的地方是他不直接提供现成的UI供用户使用而是提供了一堆基类或者说是模版类供用户继承从而实现自己的皮肤。当然他还提供一个开源的默认皮肤供开发者参考。
AlternativaGUI的定位是游戏UI框架,因此他里面的许多设计也都体现了他的灵活,高效与轻量。
目前网上AlternativaGUI的中文资料很少(外文的没搜过不敢说),搜索排名第一的是天地会的Wiki,但是里面的链接好像是失效了找了半天也没找到什么东西。
AlternativaGUI确实还提供了一个“一句话”文档,告诉我的我都知道,我不知道的一句没提!!坑爹的文档。。
但AlternativaGUI的好处是api超简洁,根本没几个方法,那哥就亲自给你动手测一测!
测试过程忽略,下面是结论,可能不能一次性更新完,有兴趣的同学可以收藏。
GUIobject:
所有可见的UI对象的基类,提供了最基本的渲染模型。
freezeHeight和freezeWidth两个标记位,如果将他们设置为true,那么在修改对象的width或者height的时候将不会调用calculateHeight/Width和draw,默认都是false。我可以想象到这样的一个使用场景,你可能要频繁修改对象的尺寸,但是不想尺寸的修改直接被渲染出来,因为你修改的很频繁啊,直接被渲染出来就会消耗没有必要的计算,况且渲染是那么得消耗资源。。当最后你确定某个尺寸的时候才恢复标记位做一次渲染。
width和height,这两个属性是直接覆盖DisplayObject的属性,但是调用他的实际效果已经和DisplayObject里的原本功能没有半毛钱关系。举例width来说明,其实他应该是这个吊样:
public function set width(value:Number):void {
if (!freezeWidth) {
_width = calculateWidth(value);
draw();
} else {
_width = value;
}
}
所以我们的width不是设置进去多少就多少,在默认情况下还需要过calculateWidth这关,然后他会进行一次draw从而把设置的宽度反映到画面上。
drawChildren():void,这个方法会先调用自己的drawGraphics()然后依次调用其子项的drawChildren(),中序遍历二叉树,然后就渲染成功了。不过最基本的GUIobject没有子项,所他基本上也就是个摆设,需要用户自己去覆盖,去实现符合方法意义的处理。在Container中系统默认的方法才有一些实际意义。
drawGraphics():void,这个方法是重绘图像,可以被直接调用也可能在drawChildren()或者其父节点爷爷节点等长辈的drawChildren()中被间接调用,其任务就是把最近的数据绘制到屏幕上,内容则由用户覆盖后自由发挥。
resize(width:int, height:int):void方法是设置height和width的集合体,但obj.height = 100;obj.width = 100;和obj.resize(100, 100);的区别是前者会导致重绘两次,后者只重绘一次,其他都一样。
calculateHeight(value:int):int和calculateWidth(value:int):int是用来控制对象的尺寸合法范围的,如上文内容,当设置width的时候value必须先传入calculateWidth,然后由calculateWidth得出合法的值才是真正的width值。我们通过重写calculateWidth来控制尺寸的合法范围。
draw():void方法用来实现由尺寸改变而产生的重绘。比如一个带有居中文本的button,当button的尺寸改变的时候会调用draw方法,我们可以在draw方法中根据button的最新尺寸重新计算文本框的位置和大小,从而保持文本框的居中。
总结:GUIobject是AlternativaGUI渲染树中的节点,某个GUIobject的尺寸改变,其直接原因是用户修改了他的width或者height,这将引发该对象的draw方法,而在draw方法中用户可能自定义了一些布局算法,有可能改变了其子项的位置和尺寸,从而间接导致子项的draw方法触发,直到叶子节点。这样就使整个显渲染树的位置得到重绘。在这个渲染框架中,还存在一个子项或者孙子项影响长辈节点尺寸的可能,当容器在重写calculateHeight和calculateWidth的时候考虑了其子项的位置尺寸以及其calculateXxxxxx,那么我们就可以让容器的大小受限于他的内容。
Container:
这是一个用于容纳显示对象的容器,他继承于GUIobject。他的主要功能是对子项进行布局。
objects:Vector.<DisplayObject>是一个子项组成的数组,其子项类型只要显示对象就好了。该数组由addChild,addChildAt,removeChild,removeChildAt四个方法进行维护。但是虽然这个属性是只读的,但是他并非返回一个数组副本,所以你可以对其中的内容进行修改。但是劝你最好别这么做,这会导致objects的内容和实际显示列表的内容不同步。这意味着有可能手动添加到objects的内容并非合法的。
addChild,addChildAt,removeChild,removeChildAt这四个方法一起讲,他们覆盖了原生的DisplayObject的四个方法,四个方法在原先的基础上增加了对objects数组的维护,每个被添加到显示列表的元素都会被添加到objects中,每个从显示列表中删除的元素也都会从objects中删除。
drawChildren():void这个方法继承于GUIobject但是Container做了重写,他首先调用自身的drawGraphics然后依次调用objects中GUIobject类型的对象的drawChildren()方法。
总结:Container是一个可管理子元素的GUIobject。嗯!就是这样。。