About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Oct

    31

    无论是在 Web 版还是在桌面 AIR 运行时环境,无论是默认的或自定义的项编辑器 itemEditor,都 发现存在这个问题:先让运行时环境失去焦点,然后再让运行时环境重新获得焦点。此时如果 DataGrid 有焦点,并且有项被选中,会发现被选中的项的项编辑器会一闪而过,虽然不影响操作,但有碍视觉效果,尤其是使用一个较大面积的自定义项编辑器时(如果是默认文本项编辑器因为面积很小甚至很难注意到它)。可以用如下方法处理:

    定义一个变量 canEnabledItemEdit 默认值为 true, 表示默认情况下允许点击单元格后自动使用项编辑器。但需要通过对 itemEditBeginning 事件加以验证:

    private function itemEditBeginningHandler(e:DataGridEvent):void
    {
      if(!canEnabledItemEdit)
     {
      e.stopImmediatePropagation();
      e.preventDefault();
     } 
    }

    与之对应的在运行时失去和获得焦点时设置 canEnabledItemEdit 的值: 

    //假装很高级的省略了一些包与类相关的代码
    NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, deactiveHandler);
    NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, activeHandler);

    private function deactiveHandler(e:Event):void
    {
     canEnabledItemEdit = false;
    }

    private function activeHandler(e:Event):void
    {
     this.callLater(callLaterHandler);
     
     function callLaterHandler():void
     {
      canEnabledItemEdit = true;
     }
    }

    Nov

    17

    任意新建一个 MXML 组件继承自 spark 版本 TextInput  组件,不添加任何扩展代码: 

    <?xml version="1.0" encoding="utf-8"?>
    <s:TextInput xmlns:fx="http://ns.adobe.com/mxml/2009" 
                 xmlns:s="library://ns.adobe.com/flex/spark" 
                 xmlns:mx="library://ns.adobe.com/flex/mx"
                 >

        <fx:Declarations>
            <!-- 将非可视元素(例如服务、值对象)放在此处 -->
        </fx:Declarations>

    </s:TextInput>

    当把这个组件应用到项目中去时,会遇到这样的 Bug 提示: 

    “String”类型的默认属性“text”有多个初始值设定项值。

    但如果把 spark 的前缀 s 换成 mx 的 TextInput  组件则完全正常。但如果样式已经经过自定义,换成 mx 则不通用。

    解决方法:

    第一种:采用纯 AS 语法继承 TextInput  ,放弃使用 MXML 语法。

    第二种:继续使用 MXML 语法,但插入任意一个已知属性,以 visible 属性为例(也可以是类似 alpha 等这样的属性):

    <?xml version="1.0" encoding="utf-8"?>
    <s:TextInput xmlns:fx="http://ns.adobe.com/mxml/2009" 
                 xmlns:s="library://ns.adobe.com/flex/spark" 
                 xmlns:mx="library://ns.adobe.com/flex/mx"
                 >

        <s:visible>true</s:visible>

        <fx:Declarations>
            <!-- 将非可视元素(例如服务、值对象)放在此处 -->
        </fx:Declarations>

    </s:TextInput>

    Oct

    7

    AcheGesture 有一个长按手势类 HoldGesture,但它在有些安卓设备中无法使用,这并不是 AcheGesture 的 Bug,也不是 Android 系统的 Bug,造成它无法正常使用的主要原因是因为安卓设备制作商太过杂乱,开发者永远都无法知道一家设备制造商与另一家设备制造商除了分辨率、精度与灵敏度等方面的区别外,还有哪些区别。

    而在 AcheGesture 中造成某些安卓设备无法使用 Hold 手势的主要原因是 Starling 中 Touch 事件的 TouchPhase.MOVED 阶段在不同安卓设备制造商对它的“定义”并不相同,比如在索尼 LT22i 移动定制版手机中,只要按住屏幕,既便没有移动手指,touch.phase 输出的值仍然是 moved 阶段:

    trace(t.phase, t.globalX, t.globalY);
    //output
    moved 80 266
    moved 80 266
    moved 80 266
    moved 80 266
    moved 80 266
    moved 80 266

    而 AcheGesture 中 HoldGesture 通过判断 phase 是否为 TouchPhase.MOVED ,进而是否中止计时器 Timer 对象,所以在这样的设备中,AcheGesture 永远不会发生 Hold/长按屏幕事件。

    虽然造成这种问题的原因与分辨率、精度以及灵敏度等无关,但解决方法基本与《Adobe AIR 移动开发,安卓设备触屏精度不准度的解决方法》一文中相同,通过阔值/容差值进行修正。以下是修正以后的类:

    package acheGesture.gestures
    {
        import flash.events.TimerEvent;
        import flash.geom.Point;
        import flash.utils.Timer;
        import acheGesture.GestureManager;
        import acheGesture.utils.GestureConfigKey;
        import acheGesture.utils.GestureType;
        import starling.events.Touch;
        import starling.events.TouchPhase;

        public class HoldGestureRecognizer extends GestureRecognizerPlugin
        {
            private var _timeThreshold:Number = 1000;
            private var _timer:Timer;
            private var _validate:Boolean;

            private var _touchBeganPoint:Point = new Point(-1,-1);//手指刚开始按下时的点坐标
            private var _touchMovePoint:Point = new Point(-1,-1);//手指开始移动的坐标
            private var _distance:Number = 10;//两个点之间的阔值/容差值

            public function HoldGestureRecognizer(priority:int=0, requireGestureRecognizerToFail:Boolean=false)
            {
                super(GestureType.HOLD, priority, requireGestureRecognizerToFail);
            }

            override public function checkGesture(ts:Vector.<Touch>):Boolean
            {
                var t:Touch = ts[0];

                if(t.phase == TouchPhase.BEGAN)
                {
                    _validate = false;
                    if(_timer == null)
                    {
                        _touchBeganPoint.x = t.globalX;
                        _touchBeganPoint.y = t.globalY;


                        _timer = new Timer(_timeThreshold, 1);
                        _timer.addEventListener(TimerEvent.TIMER, onHoldGestureValidate);
                        _timer.reset();
                        _timer.start();
                    }
                    _failed = false;
                }
                if(t.phase == TouchPhase.MOVED) 
                {
                    _touchMovePoint.x = t.globalX;
                    _touchMovePoint.y = t.globalY;
                    //如果两点之间的距离大于容差值
                    if(Point.distance(_touchBeganPoint,_touchMovePoint) > _distance)
                    {
                        _validate = false;
                        removeTimer();
                        if(!_validate) 
                            _failed = true;
                    }
                }
                if(t.phase == TouchPhase.ENDED) 
                {
                    _validate = false;
                    removeTimer();
                    _touchBeganPoint.x = -1;
                    _touchBeganPoint.y = -1;
                }
                return _validate;
            }

            private function removeTimer():void
            {
                if(_timer)
                {
                    _timer.stop();
                    _timer.removeEventListener(TimerEvent.TIMER, onHoldGestureValidate);
                    _timer = null;
                }
            }

            override public function _onInitGesture(callback:Object, config:Object, g:GestureManager):Boolean
            {
                if(config[GestureConfigKey.TIME_THRESHOLD] != null) 
                    _timeThreshold = Number(config[GestureConfigKey.TIME_THRESHOLD]);
                return super._onInitGesture(callback, config, g);
            }

            private function onHoldGestureValidate(e:TimerEvent):void
            {
                if(_g._firstG.r && !_g.allowSimultaneous) 
                    return;
                removeTimer();
                _validate = true;
                _g.gestureRecognizerStateChange(this._gestureType, true);
            }
        }
    }

    备注:不要试图去为安卓用户开发任何基于精度或灵敏度的 APP(除非 APP 是量身定制量,只在固定的厂商和型号的设备上运行),尤其是应用的用户可能会集中在中低端机型或山寨机型情况下。开发者应珍爱生命,远离安卓开发——把所有的时间和精力放在自己的产品算法和业务逻辑上,不要把时间和精力放在各种安卓厂商生产的不同机型的调试和测试过程中。

    Jan

    25

    Adobe AIR SDK 4.0 在 Release 版本最新发布后进行了测试,在 使用 -useLegacyAOT no 参数后(新的 halfmoon 编译器),确实让 AOT 编译模式加速了 5-10 倍,基本上可以说跟解析模式的打包速度差不多了。

    但在实际测试过程中发现了一个严重的 Bug,在中文系统中,有时会提示“命令行太长”或“输入行太长”,并且会带有以下英文提示:

    Compilation failed while executing : compile-abc

    当然,它并不是真的因为命令行或输入行太长造成的,因为既便用户全部使用系统环境来缩短命令行,也会是相同的提示;换句话说,只要不使用“ -useLegacyAOT no”参数(不使用 halfmoon 编译器),使用更长的命令行也可以正常编译。

    搜索之后,发现早在 Beta 版本时就已经有人在 Adobe 官方论坛提交过这个 Bug,但在 Adobe 发布 Release 版本时并未修复这个问题。Release 版本发布之后仍然有许多其他人在 Adobe 官方论坛提交了这个问题,称之为“毫无逻辑”的 Bug。

    所以目前的 4.0 版本如果在使用 “-useLegacyAOT no”参数之后,出现了这个问题,除了禁用“ -useLegacyAOT no”参数,没有任何解决方法(当然,编译的时间也会跟 3.9 以前的版本一样长),只能等待 Adobe 更新 AIR SDK 修复这个问题。

    More...

    Jan

    21

    Adobe AIR 移动应用程序自动侦听舞台旋转和舞台的 resize 事件,然后旋转移动设备几次后,会发现 TextField 的自适应布局功能计算出来的尺寸会有问题。可以使用一个延迟刷新的 CallLater 类解决这样的问题(在其它一些情况中,比如 autoSize 属性更改、文本样式更改,或 text 属性与 htmlText 属性混合更改时,TextField 对象的尺寸属性往往会有一些“异步”的效果出现,都可以使用 CallLater 类解决)。

    More...

    Jan

    12

    Flash Builder (Flex / FB)4.7 版本安装后两个月的使用过程中,遇到过以下几个问题(但不代表全部):

    1、按 Ctrl 加鼠标点击查找定义的时候,返回的位置有时会完全不正确。

    2、在使用 Alt + "/" 代码提示导入一个类,或直接使用 import 导入某个类之后,并且使用了这个类后,有时它会给出一个黄色叹号提示,表示这个类未在当前文档中使用(其实已经使用了)。

    3、在 if 的判断语句中如果使用赋值号,它会给出一个非常友好的黄色叹号,但有时候开发者是需要在精减语句的情况下使用这种编码方式,个人表示不喜欢。

    比如 a 和 b 都是一个数组类型, if ( a=b || a.length ),这比在外部先赋值 a=b ,再判断 if (a || a.length)要爽快的多。

    4、在针对 FlexFrame 的 MXML 中设置的一些文本样式,编译后显示不正确,需要使用对应的 AS 重置这些样式才会正确显示。

    5、在编写代码、查找代码、使用功能组合键时,有时候会弹出一些 Java 相关的错误提示。

    以上这些问题在 FB 4.6 版本中并没有发现过以上这些问题,看来新版本未必好使(个人猜测的原因:FB 4.6 在2011年年底发布,随后在一个月内裁员了 750 人,其中大部份是 Flex 开发部门人员,并将 Flex SDK 部份赠送开源组织 Apache。而未被裁员留下的那些开发人员未必能够发现 Flex 的每一种编码情况和每一个遇到的问题,修正 Bug 也变的非常缓慢了)。

    Mar

    12

    Flash 无法输入中文的修正方法

    • 0 Comments
    • Flash Platform

     在某些运行模式或运行时环境中,Flash 有一个 Bug,文本框与键盘的交互模式会无法输入中文(包括日文等带有输入法状态栏的输入模式),只要对 TextField 文本框实例的 FocusEvent.FOCUS_IN 事件添加一个侦听器即可,侦听器中将 IME.enabled 设置为 true

    Mar

    12

     在 Adobe AIR 运行时环境中,Window 是 AIR 桌面应用程序中其它窗口的顶级容器,它除了最大化窗口功能(maximize())外,还可以使用全屏功能(StageDisplayState.FULL_SCREEN_INTERACTIVE)。但在全屏功能中它有一个“小陷井”,在某些情况下,如果按了ESC键或CTRL+S键这后,它有可能会退出全屏模式,甚至还会让窗口变的只剩两个滚动条(这应该是 Adobe AIR Window 留下的Bug)。不过可以通过对舞台(stage)实例添加全局的键盘事件(KeyboardEvent.KEY_DOWN)来屏蔽这情况:

    if(e.keyCode == Keyboard.ESCAPE)
    e.preventDefault();
    if(e.keyCode == 83 && e.ctrlKey)
    e.preventDefault()

    More...

    Apr

    16

    可以在使用 setSelected ()方法后,继续使用 getTextRunInfo() 方法修正。也可以延迟刷新的方式来修正这个Bug(比如使用 UIComponent 的 callLater() 方法延迟刷新)。

    TextSnapshot 实例具有弱引用的特征,如果是局域变量或引用更新,需要使用数组或泛型等保存引用,以防止被垃圾回收。

    样例问题:http://forums.adobe.com/message/4245071?tstart=38

    Dec

    8

    Flash无论是ActionScript2或3编程,它的刷新渲染方式都是基于帧的渲染,很多闪客ASer都认为这是导致Flash编程执行效率低下的主要原因。但本人也在这里提出一种看法,即:很多Flash的BUG也是基于这种帧刷新的方法产生的(个人认为 Flash ActionScript2/3 是一种“邪恶”的编程语言)。 

    Stage.scaleMode = "noScale";
    Stage.align = "TL";
    //生成红色按扭用于切换全屏与窗口
    var square_mc:MovieClip = createEmptyMovieClip("square_mc", getNextHighestDepth());
    square_mc.beginFill(0xFF0000);
    square_mc.moveTo(10,10);
    square_mc.lineTo(100,10);
    square_mc.lineTo(100,100);
    square_mc.lineTo(10,100);
    square_mc.lineTo(10,10);
    square_mc.endFill();
    square_mc.onRelease = function() {
     Stage.displayState = (Stage.displayState == "normal" ? "fullScreen" : "normal");
    };
    //注销以下这一段将在FLASH的一些新版本中产生BUG
    /*var myListener:Object = new Object();
    myListener.onResize = function() {
     Stage.align = "TL";
     onEnterFrame = function () {
      Stage.align = "TL";
      if (Stage.align == "TL") {
       delete onEnterFrame;
      }
     };
    };
    Stage.addListener(myListener);*/

    //TXT用于显示舞台宽度
    var txt:TextField = createTextField("txt", getNextHighestDepth(), 100, 100, 100, 100);
    //实时检测舞台大小
    square_mc.onEnterFrame = function() {
     txt.text = String(Stage.width);
    };

    这样的BUG是否“邪恶”?解决像这类BUG的方法,就是使用延迟并重置属性,如使用setTimeout 或 onEnterFrame等。还有一些像AS3的主类为外部文件类时,在初始化时也会产生类似的BUG,可以通过这种延迟方法解决。像 setSelectColor 方法也许并不常用,但 TextSnapshot 类在正常使用的情况下,唯有这个类中的 setSelectColor 方法经常不能正常使用,也可以通过延迟的方法来解决。

    注:1、AS2 中使onEnterFrame 后需要 delete 将它删除。AS3中使用Event.ENTER_FRAME事件后需要使用相应的 addEventListener 取消侦听器。2、Flex中的一些框架组件有时候用Event.ENTER_FRAME的延迟并不一定能修正这个BUG,这时候可以试试setTimeout ,哪怕它的时间延迟设定的是0.001秒。这说明有些BUG的修正方法并不决定于开发人员使用的推迟时间长短,而是决定于使用的方法。