+ -
当前位置:首页 → 问答吧 → 让Flash自带的滚动条支持设置宽度的方法

让Flash自带的滚动条支持设置宽度的方法

时间:2010-08-12

来源:互联网

相信从事Flash/Flex,乃至其他应用程序开发的朋友或多或少都有这样的体会:一个项目的整体进度要达到95%,并不需要耗费太多精力,而剩下的5%却占用了你开发总时间的95%才得以完成。而这5%的工作,不是弥补程序里的小缺陷,就是修复一些令人苦笑不得的Bug。

不可否认,程序中的Bug相当一部分系因开发人员思维不够慎密而造成的。然而,现在能使用机器语言进行编程的人可谓凤毛麟角,我们需要依赖于系统平台,编译器,甚至解释器才可以进行编程并得到成品。所有的依赖因素,都不可避免地存在漏洞,随时都有可能影响到程序员的开发进程。

AS开发也不例外,尽管FlashPlayer具有跨平台的特性,但它本身的bug,就已经让不少Aser忍无可忍,如果要结合JS,则还需要考虑浏览器的兼容问题。一个项目,时间往往要浪费在处理这些问题上,幸亏大多数客户不懂技术,看到整体进度基本过关,即使项目一拖再拖,客户也是愿意等待的。

目前我的时间相对宽松一些,故计划把以前遇到过的一些问题进行整理,然后在此处发帖,并提出解决方案以抛砖引玉。

第一帖打算先向大家汇报一个密码文本框的Bug。按常规来讲,密码字段不可以通过右键菜单及快捷键等基本方法进行复制,但Flash的密码文本却没有屏蔽掉Ctrl+C,在非密码字段粘贴一下,密码字符串便一览无余。这个Adode公司,竟连密码框最基本的安全意识都缺乏,枉他还做了几年的安全沙箱。曾计划向Adobe提交此Bug,无奈国内访问速度过慢,再者密码框查看工具也已经比较成熟,我就没再考虑提交了。

按我原来的安排,今天先把自己为修复此Bug而扩展的PasswordTextField类在本论坛公开,不过我今天很意外地发现,FlashPlayer10.1已经对此进行了修正,我的PasswordTextField也可以功成身退了。

所以,今天向各位汇报的,是另一个问题。为了让Adobe用户开发更为方便,Adobe的AS程序员为Flash及Flex都开发了一套UI组件,基本上能满足中小型Web应用程序的需求。但是,这当中包含的一些小Bug非常让AS程序员头痛,有的人为了修正它,调用组件后,写一些有针对性的函数去处理,有的人则干脆放弃自带组件,进行自主开发,或者用其他组件库如Aswing、apple等,有的则退而求其次,说服其他部门的同事,在非技术层面上采用其他方案代替。

由于Adobe的组件开源,我们还可以通过直接修改代码,重新编译。但我在使用FlashCS5的过程中,修改组件代码,重新编译,组件并没有发生任何变化,在ComponentShim里编译swc,也得不到我修改后的结果,将这个类库的目录添加到项目的源路径也一样不奏效,最后尝试反编译来修改,结果报出一堆错误。

无奈之下,我只能选择扩展原有类,通过重写某些方法来修复这些带Bug的组件。

Flash/Flex自带的UIScrollBar不支持纵滚动条宽度和横滚动条高度的设置,把设置尺寸和修改样式的函数通通试了一遍,没有一个可以达到目的。即使用Embed标签嵌入尺寸不等于默认值的图片,发布后,组件也会自动将图片调整为默认尺寸。

查看ScrollBar(UIScrollBar的父类)类的源代码,发现有以下几处代码写得很死:
复制内容到剪贴板
代码:
public static const WIDTH:Number = 15;
滚动条宽度写死在了一个常数上,因此无法在运行时进行设置。下面我们再来观察绘制组件的相关代码:
复制内容到剪贴板
代码:
/**
         * @private (protected)
         *
         * @langversion 3.0
         * @playerversion Flash 9.0.28.0
         */        
        override protected function configUI():void {
            super.configUI();
            
            track = new BaseButton();
            track.move(0,14);
            track.useHandCursor = false;
            track.autoRepeat = true;
            track.focusEnabled = false;
            addChild(track);
            thumb = new LabelButton();
            thumb.label = "";
            thumb.setSize(WIDTH,15);
            thumb.move(0,15);
            thumb.focusEnabled = false;
            addChild(thumb);
            
            downArrow = new BaseButton();
            downArrow.setSize(WIDTH,14);
            downArrow.autoRepeat = true;
            downArrow.focusEnabled = false;
            addChild(downArrow);
            
            upArrow = new BaseButton();
            upArrow.setSize(WIDTH,14);
            upArrow.move(0,0);
            upArrow.autoRepeat = true;
            upArrow.focusEnabled = false;
            addChild(upArrow);
            
            upArrow.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
            downArrow.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
            track.addEventListener(ComponentEvent.BUTTON_DOWN,scrollPressHandler,false,0,true);
            thumb.addEventListener(MouseEvent.MOUSE_DOWN,thumbPressHandler,false,0,true);
            
            enabled = false;
        }
至此真相水落石出,轨道,按钮的尺寸全部写死在一个常数上。

与此同时,draw方法也没有调用过setSize函数所设定的width属性,整个重绘跟width属性无关(对纵滚动条而言)
复制内容到剪贴板
代码:
/**
         * @private (protected)
         *
         * @langversion 3.0
         * @playerversion Flash 9.0.28.0
         */
        override protected function draw():void {    
            if (isInvalid(InvalidationType.SIZE)) {
                var h:Number = super.height;
                downArrow.move(0,  Math.max(upArrow.height, h-downArrow.height));
                track.setSize(WIDTH, Math.max(0, h-(downArrow.height + upArrow.height)));
                updateThumb();
            }
            if (isInvalid(InvalidationType.STYLES,InvalidationType.STATE)) {
                setStyles();
            }
            // Call drawNow on nested components to get around problems with nested render events:
            downArrow.drawNow();
            upArrow.drawNow();
            track.drawNow();
            thumb.drawNow();
            validate();
        }
所以,要让组件支持滚动条宽度设置,必须重写这两个函数。
在我的源码里,几乎没有调用过super,因为常数写得过于分散,直接调用超类函数再添加自己的修正代码也特别麻烦。

由于BaseScrollPane(及其子类),TextArea等类均应用了滚动条,所以若要让那些组件的滚动条支持宽度设置,同样需要重写相应的重绘方法,同时把ScrollBar或者UIScrollBar组件换成你扩展过的。

下面是我扩展过的ScrollBar代码:
复制内容到剪贴板
代码:
package com.hbro.controls {
    
    import fl.controls.ScrollBar;
    import fl.core.InvalidationType;
    
    public class ResizableScrollBar extends ScrollBar{
        
        public function ResizableScrollBar() {
            // constructor code
            super();
        }
        
        override protected function draw():void {                
        
            //代码从ScrollBar类拷贝过来,将常数换成与width有关的变量,以使得在调用setSize或者设置width的时候,可以改变宽度
            if (isInvalid(InvalidationType.SIZE)) {
                var h:Number = super.height;
                
                //滚动条按钮按宽度进行设置,源程序写死了一个常数,导致该大小无法改变,有兴趣的朋友可以在此基础上进行修改,让按钮区域可以不呈现为正方形。
                downArrow.setSize(_width,_width);
                upArrow.setSize(_width,_width);
                downArrow.move(0,  Math.max(upArrow.height, h-downArrow.height));
                
                //轨道宽度也要进行设置
                track.move(0,_width);
                track.setSize(_width, Math.max(0, h-(downArrow.height + upArrow.height)));
                thumb.setSize(_width,thumb.height);
                updateThumb();
            }
            if (isInvalid(InvalidationType.STYLES,InvalidationType.STATE)) {
                setStyles();
            }
            // Call drawNow on nested components to get around problems with nested render events:
            downArrow.drawNow();
            upArrow.drawNow();
            track.drawNow();
            thumb.drawNow();
            validate();
        }
    }
    
}
本人发布的附件包还包含了UIScrollBar,List及TextArea类的扩展,读者如有兴趣或需要,可以用类似的方法重写其他几个跟滚动条有关的组件(Flash或Flex组件均可)中相应的函数。

调用这些类时,必须保证库里包含了父类的组件,因为调用父类时同样需要库里存在组件的情况下才可以正常编译。

附件

支持滚动条宽度设置的List组件.jpg (26.09 KB)

2010-8-12 15:10

可缩放滚动条.rar (555.97 KB)

2010-8-12 15:10, 下载次数: 65

作者: HBrO   发布时间: 2010-08-12

  支持,大虾厉害
我就从来不敢用组件

作者: flash023   发布时间: 2010-08-12

以前我也不用的,自己写。
但当我两年前发现自己写的那套组件在FlashPlayer10下有太多的Bug以后,深受打击,就开始尝试去使用默认组件了。

作者: HBrO   发布时间: 2010-08-12

  向大虾学习

作者: flash023   发布时间: 2010-08-12

作者: HBrO   发布时间: 2010-08-12

晕,加分加错楼层了……

到目前为止我所有的项目都只有两种选择:用自己的组件库,直接使用FLEX

作者: jimohuoshan   发布时间: 2010-08-14

哈哈,HBro赚到了。我经常使用的组件就一个:FlvPlayback,其他自带的组件没用过。

作者: liaoruilu   发布时间: 2010-08-14

学习了。

作者: xtpz   发布时间: 2010-08-14

火山,Flex和Flash不分家,Flash组件有的缺陷和Bug,到Flex里也一样有。
自己写组件库是个明智的选择,但是我比以前懒了很多。

作者: HBrO   发布时间: 2010-08-17

比较纳闷为啥fl跟fx都限制了这个属性,雅虎的astra也没做相应修改. 郁闷,这东东我正也需要,谢谢老牛咯  +1000000

作者: 0xFF336699   发布时间: 2011-07-19