只学一点点:我的技术学习策略

李敖有首诗叫《只爱一点点》 :

不爱那么多,

只爱一点点;

别人的爱情像海深,

我的爱情浅。

不爱那么多,

只爱一点点;

别人的爱情像天长,

我的爱情短。

不爱那么多,

只爱一点点;

别人眉来又眼去,

我只偷看你一眼。

一点足够。在黄易的大唐双龙传中有个说法叫《遁去的一》,也就是说任何事情在纷杂万象之中都有一个消失的一,把这个消失的一找到,就可以事半功倍。

在学技术中,很多人纠结于掌握与精通。掌握是能够熟练的使用该技术实现自己的目标,而精通,则是对该技术的常用及半常用的场景都熟悉,能够处理常见或非常见的问题,是广泛的掌握。

在宅男和腐女眼中,万事万物皆为攻受。学习务必精通,则是绝世小受,学习只求掌握,则是偏向于攻。孙子曰:善攻者动于九天之上,善守(受)者藏于九地之下。下面看看动于九天之上的学习方法。

作为一个上个世纪就开始写网页的程序员,你如果问我这个css怎么写,这个js怎么写,我的回答一般就是两个字:“不会”。做为一个从.net 1.0就开始写C#程序的程序员,如果你问常见的.net问题,50%情况下我的回答还是“不会”或者“查MSDN”。有不少人加我QQ讨论技术问题,我最多的回答是“不会”,“不知道”,“Google”。时至如今,也就会些用了理所当然就能记住的知识,其它的都不会,IDE的快捷键也记不住几个。当然,也有碰巧那个东西我懂的,这种情况极少。

技术是来解决问题的,不是增加心智负担的。承担进攻任务的行军不会带太多的累赘。我的开发任务中数据库、查询类的不重要,linq不用学,自从接触代码生成后,ORM的也全部都扔了,因为ORM需要学习,且可控性没有代码生成的好。自从项目主要是图形图像方面的后,asp.net等也都丢了,因为这类项目需求变动大、技术支持困难。直到后来才找到.net对我而言的遁去的一:unsafe + 指针。有了unsafe + 指针,图像程序性能大增,相比C/C++而言,生产力也得到了极大的提高——什么新东西都不用学(指针还没忘记)。

知识是基于过去经验的总结,而我们面对的是未来,因此,对于过往知识需要谨慎的辨识,对于他人经验需要参考性的采纳。MSDN中明白的说,不鼓励使用unsafe,而在.net图像程序中大量的使用后,才能感觉到它的爽。如果看到MSDN上不推荐用,看见别人也几乎不这么用,自己就给自己设置禁区,那我就找不到这个遁去的一。

下面是个更深刻的例子。今年应该是我写Flash程序的第三个年头。俺,是一个不会FlashFlash程序员。你如果让我用Flash CS工具做一个动画,很抱歉,不会。那么看看,我会哪些?我学了哪些?我能做什么?做这些我相对于别人有哪些优势?从这个例子看看什么是进攻式学习。

普遍看来,Flash是一个动画工具。全球数百万Flash动画设计师。好吧,俺美工差,如果它是个动画工具,俺就不玩了。

在我最初看来,Flash是一个运行在绝大多数PC机上的虚拟机平台,擅长处理图形图像,可以用它来快速开发程序。这样看,就可以玩玩它。为什么?图形图像类应用是我给自己确立的方向,而Flash是一个适合的平台。

这样的认识还没有触及遁去的一。随着开发经验的增加,一个遁去的一开始浮现:

Flash是一个最简单的虚拟机,它只封装了最基本的操作(图形图像、声音、视频、XML以及现在的3D),连Button控件都没有,凡是可有可没有的都没有。

用普通的眼光看,这个虚拟机简单、弱小。换一种方式看:尺寸小,平台小,容易移植。用html5/js来写一套Flash的基本API也没多少代码。因此,Flash/AIR才这么容易的打入iOS之中,且各类平台间Flash代码保持非常好的兼容性。

Flash提供了一套简洁的API,跨各种平台。Flash以库的形式扩展(这一点与.Net很大不同),Flash CS工具里自带了一套简单、开源的UI控件库,Flex则提供了一套复杂的、全功能的UI库,这些都是Flash平台外部的(这也与.Net不同,WPF是在SDK里面的,而不是外面)。在平台外部,就拥有了很好的灵活性。

这个简单的弱小的小玩意怎么能算遁去的一呢?

算不上!

它充其量就是一个灰尘大小的卵细胞。

下面,一个微不足道的、看似毫无关联的玩意出场了:数据绑定。它就像一个小蝌蚪一样,向卵细胞游啊游,在两者接触的瞬间,一个生命诞生了!

Flash开发遁去的一就是Flash的底层API + 数据绑定。

Flash底层API很简单很少,各大平台都支持(Web,桌面,移动)。它就是中国移动全球通,什么地方都有它——我能!

光能还不行,直接用Flash底层API开发,就像用GDI+一笔笔绘制一样,麻烦的要命,直到数据绑定出现,数据绑定让基于Flash API的开发有了质的飞跃——它好我也好!

因此,掌握Flash只需要掌握两个东西:底层API和数据绑定,剩下的都是细枝末节的,用的时候查文档和搜索引擎就可以了。我们需要学的东西是多么的少,而我们能做的事情是多么的多!

首先,得学习开发语言。Flash平台的官方开发语言是actionscript3,简称as3,每当说起as3时,人们总会谈起as2,你就当as2从没出现过,了解as2一点用都没有,不闻、不问、不看。

as3和主流开发语言很类似。package 机制、类机制和java相似,继承是extends,实现接口是implements。区别:

(1)变量声明是var i:int;函数声明是:function foo(i:int):int; 不支持方法重载,支持默认参数。函数可以作为参数传递。支持闭包。

(2)GetterSetter分别为:function get foo():int; function set foo(i:int):int;

(3)抛出事件:dispatchEvent;监听事件addEventListeneraddEventListener。事件支持弱引用。

(4)for each可以遍历集合;

(5)支持动态类,Object是动态类,for可以遍历Object: 

 

for (var key:String in obj) 
{
...
}

 

(6)[  ]里写元数据。常用的有三个:事件申明,嵌入资源和数据绑定:

数据绑定是 [Bindable],这个在后面会详述。

嵌入资源的例子一看就明白:

[Embed(source="assets/blackStyle/iconPlayStart36.png")]

private var buttonForwardPlay36:Class;

事件申明用在类中,申明之后,IDE会对该类给出对应事件的智能提示,例子:

[Event(name="inited", type="flash.events.Event")] 

as3很快就学会了,拿本语法书,扫一眼就行了。不用Flash CS工具的话,主流IDE就是Flash Builder,它是基于Eclipse开发的,用过Eclipse的拿过来就会用。

 

下面进入主题:Flash API和数据绑定。需要掌握的Flash API

(1)绘制的API:绘制线、绘制曲线、填充/梯度填充、蒙版、混合模式(貌似除了蒙版外,Html5都有!)

(2)滤镜和变换

(3)文本处理:TextField

(4)核心UI类:Sprite、它的生命周期及对交互的响应

上面这些是我们的钢筋水泥,下面,就用这些钢筋水泥来搭建我们自己的应用。有人可能会问:控件呢?有了数据绑定,我们并不需要控件,或者换句话说,有了数据绑定,我们可以很容易由底层API搭建自己需要的控件。

数据绑定非常容易!

数据绑定是FlexmxmlFlex描述界面的语言)编译器提供的一个功能。下面,我们只用Flex的 mxml编译器,而不用Flex的任何控件,来从Flash API搭建我们自己的控件或其它应用。Mxml就不介绍了,看一眼就会了。下面是一个mxml中数据绑定的例子:

 

    <shapes:Rectangle id="background" width="{width}" height="{height}"
                       corner="{bgCorner}" corners="{bgCorners}"
                       color="{bgColor}"
                       alpha="{bgEnabled?bgAlpha:bgAlpha*0.3}"
                       borderColor="{bgBorderColor}"
                       borderThickness="{bgBorderThickness}"
                       fillAlpha="{bgFillAlpha}" borderAlpha="{bgBorderAlpha}"
                       />

 

很简单、很容易理解、理解了就再也忘不了:大括号{}中的就是数据绑定内容,{}中的所有可绑定的变量构成绑定链,绑定链上的绑定源出现了任何变化,都会激发运算,将运算结果付给被绑定的字段。

如果给一个类加了元数据[Bindable],则该类实例的字段和getter/setter就成了绑定源。如果不想把全部字段和getter/setter弄成绑定源,可对字段或setter单独增加元数据[Bindable]

这个数据绑定比WPF/SL的数据绑定简洁多了、易用多了。

下面,就靠这些开始征程。

先解决多语言的问题:

 

View Code
package 
{
    import orc.common.RpcRequest;

    public dynamic class l extends Object
    {
        [Bindable]
        public static var i:l = new l();
        
        public function s(key:String, defaultString:String = null):String
        {
            return getString(key,defaultString);
        }
        
        public static function s(key:String, defaultString:String = null):String
        {
            return i.s(key,defaultString);
        }

        public function getString(key:String, defaultString:String = null):String
        {
            if(this.hasOwnProperty(key)==false
            {
                var lowKey:String = key.toLowerCase();
                if(this.hasOwnProperty(lowKey) == false)
                {
                    return defaultString ? defaultString : key;    
                }
                else
                {
                    return this[lowKey];
                }
            }
            else
            {
                return this[key];
            }
        }
        
        public static function loadRemote(url:String, callback:Function = null, failCallback:Function = null):void
        {
            new RpcRequest(url, null,
                function(obj:Object):void
                {
                    loadXml(new XML(obj));
                    if(callback != null) callback();
                },
                failCallback
            );
        }
        
        public static function loadXml(xml:XML):void
        {
            if(xml == nullreturn;
            
            var lang:l = new l();
            
            // 第一遍
            for each(var node: XML in xml.item)
            {
                lang[node.@key]=String(node.@value);
            }
            
            // 第二遍,存储小写的key
            for each(var node: XML in xml.item)
            {
                var lkey:String = String(node.@key).toLowerCase();
                if(lang.hasOwnProperty(lkey) == false)
                {
                    lang[lkey] = String(node.@value); 
                }
            }
            
            i = lang;
        }
    }
}

RpcRequest 的代码就不贴了,它的功能就是从url取回个xml文件。这个类在根命名空间中,这样不用import就能用了。名字是l,代表language,有一个静态实例i,代表instance,它设为可Bindable,方法s代表取的是stringXml文件中存储的是键值对,这样写:

<Button label="{l.i.s('Yes')}" /> 

就绑定了多语言,如果不加载任何语言文件的话,显示的是“Yes”,如果加载了的话,如果该文件中存在键“Yes”,则加载对应的值,如果不存在,则寻找是否有小写后为“yes”的键,加载对应的值,如果都不存在,则显示“Yes”。而当更改语言时,由于i发生了变化,由于数据绑定的关系,该Buttonlabel值也马上得到了更新。

寥寥几行代码就实现了多语言解决方案。

接着是三个基础类:ApplicationBaseComponent 和 BaseContainerApplication 顾名思义,是App的入口类,提供了一些基本的功能。BaseComponent UI类的基类。BaseContainer 是容器类的基类。这三个类的代码如下:

 

View Code
package orc.common
{
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    
    import mx.binding.utils.BindingUtils;
    import mx.core.Application;
    import mx.events.PropertyChangeEvent;
    
    [DefaultProperty( "children" )]
    [Bindable]
    [Event(name="inited", type="flash.events.Event")] 
    public class Application extends Sprite
    {
        protected var _width:Number = 0;
        protected var _height:Number = 0;
        
        public var fillMode:Boolean = true;
        
        private var inited:Boolean = false;
        
        public static var instance : Application = null;
        
        public function Application()
        {
            super();
            x = 0;
            y = 0;
            instance = this;
            if(stage != null)
            {
                stage.showDefaultContextMenu = false;
                stage.align = StageAlign.TOP_LEFT;
                stage.scaleMode = StageScaleMode.NO_SCALE;
            }
            addEventListener(Event.ENTER_FRAME, onInvalidate);
        }
        
        private var _children:Vector.<DisplayObject>;
        private var childrenChanged:Boolean = false;
        
        public function get children():Vector.<DisplayObject>
        {
            return _children;
        }
        
        public function set children( value:Vector.<DisplayObject> ):void
        {
            if ( _children != value )
            {
                _children = value;
                childrenChanged = true;
                invalidate();
            }
        }
        
        protected function invalidate():void
        {
            removeEventListener(Event.ENTER_FRAME, onInvalidate);
            addEventListener(Event.ENTER_FRAME, onInvalidate);
        }
        
        protected function onStageResize(event:Event):void
        {
            if(fillMode == true)
            {
                if(this.width != stage.stageWidth) this.width = stage.stageWidth;
                if(this.height != stage.stageHeight) this.height = stage.stageHeight;
            }
        }
        
        protected function onInvalidate(event:Event) : void
        {
            if(fillMode == true && stage.stageWidth > 0)
            {
                if(this.width != stage.stageWidth) this.width = stage.stageWidth;
                if(this.height != stage.stageHeight) this.height = stage.stageHeight;
            }
            
            if(stage.hasEventListener(Event.RESIZE) == true)
            {
                stage.removeEventListener(Event.RESIZE, onStageResize);
            }
            
            stage.addEventListener(Event.RESIZE, onStageResize);
            
            if ( childrenChanged )
            {
                while ( numChildren > 0 )
                {
                    removeChildAt( 0 );
                }
                
                for each ( var child:DisplayObject in children )
                {
                    addChild( child );
                }
                
                childrenChanged = false;
            }
            
            removeEventListener(Event.ENTER_FRAME, onInvalidate);
            
            if(inited == false)
            {
                inited = true;
                this.dispatchEvent(new Event("inited"));
            }
        }
        
        override public function set width(w:Number):void
        {
            _width = w;
            invalidate();
            dispatchEvent(new Event(Event.RESIZE));
        }

        override public function get width():Number
        {
            return _width;
        }
        
        override public function set height(h:Number):void
        {
            _height = h;
            invalidate();
            dispatchEvent(new Event(Event.RESIZE));
        }

        override public function get height():Number
        {
            return _height;
        }
        
        override public function set x(value:Number):void
        {
            super.x = Math.round(value);
        }
        
        override public function set y(value:Number):void
        {
            super.y = Math.round(value);
        }
        
        public function removeAllChildren():void
        {
            while(this.numChildren > 0)
            {
                this.removeChildAt(0);
            }
            
            if(this._children != null)
            {
                this._children = null;
                childrenChanged = true;
            }
        }
    }
}

package orc.common
{
    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.DropShadowFilter;
    
    import orc.containers.PopUpCanvas;
    import orc.utils.CallLaterHelper;
    import orc.utils.MouseHelper;
    
    [Bindable]
    [Event(name="resize", type="flash.events.Event")] 
    [Event(name="mouseStick",type="flash.events.Event")]
    [Event(name="closed",type="flash.events.Event")]
    [Event(name="draw",type="flash.events.Event")]
    public class BaseComponent extends Sprite
    {
        protected var _width:Number = 0;
        protected var _height:Number = 0;
        protected var _tag:int = -1;
        protected var _enabled:Boolean = true;
        
        public static const DRAW:String = "draw";
        
        public var maskCanvas:PopUpCanvas;

        private var _mouseHelper:MouseHelper;

        private function get mouseHelper():MouseHelper
        {
            if(_mouseHelper == null) _mouseHelper = new MouseHelper();
            return _mouseHelper;
        }
        
        public function get mouseStickIntervalMiniSeconds():uint
        {
            return mouseHelper.stickHelper.intervalMiniSeconds;
        }

        public function set mouseStickIntervalMiniSeconds(value:uint):void
        {
            mouseHelper.stickHelper.intervalMiniSeconds = value;
        }
        
        private var _enableMouseStick:Boolean = false;

        public function get enableMouseStick():Boolean
        {
            return _enableMouseStick;
        }

        public function set enableMouseStick(value:Boolean):void
        {
            _enableMouseStick = value;
            if(value == true)
            {
                var self:BaseComponent = this;
                mouseHelper.stickHelper.bind(this);
                mouseHelper.stickHelper.callback = 
                    function():void
                    {
                        self.dispatchEvent(new Event("mouseStick"));
                    };
            }
            else
            {
                mouseHelper.stickHelper.unbind();
            }
        }
        
        public function show(x:Number = NaN, y:Number = NaN):void
        {
            var pop:PopUpCanvas = new PopUpCanvas();
            pop.show();
            pop.setContent(this,x,y);
        }
        
        public function showDialog(x:Number = NaN, y:Number = NaN):void
        {
            var pop:PopUpCanvas = new PopUpCanvas();
            pop.showDialog();    
            pop.setContent(this,x,y);
        }
                
        public function BaseComponent(parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number =  0)
        {
            move(xpos, ypos);
            if(parent != null)
            {
                parent.addChild(this);
            }
            init();
        }
        
        protected function init():void
        {
            addChildren();
            invalidate();
        }
        
        protected function addChildren():void
        {
        }
        
        protected function invalidate():void
        {
            removeEventListener(Event.ENTER_FRAME, onInvalidate);
            addEventListener(Event.ENTER_FRAME, onInvalidate);
        }
        
        protected function getShadow(dist:Number, knockout:Boolean = false):DropShadowFilter
        {
            return new DropShadowFilter(dist, 45, Style.DROPSHADOW, 1, dist, dist, .31, knockout);
        }
        
        public static function initStage(stage:Stage):void
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
        }
        
        public function move(xpos:Number, ypos:Number):void
        {
            x = Math.round(xpos);
            y = Math.round(ypos);
        }
        
        public function setSize(w:Number, h:Number):void
        {
            _width = w;
            _height = h;
            invalidate();
        }
        
        public function draw():void
        {
            dispatchEvent(new Event(BaseComponent.DRAW));
        }
        
        protected function onInvalidate(event:Event):void
        {
            removeEventListener(Event.ENTER_FRAME, onInvalidate);
            draw();
        }
        
        override public function set width(w:Number):void
        {
            _width = w;
            invalidate();
            dispatchEvent(new Event(Event.RESIZE));
        }
        
        override public function get width():Number
        {
            return _width;
        }
        
        override public function set height(h:Number):void
        {
            _height = h;
            invalidate();
            dispatchEvent(new Event(Event.RESIZE));
        }
        
        override public function get height():Number
        {
            return _height;
        }
        
        public function set tag(value:int):void
        {
            _tag = value;
        }
        
        public function get tag():int
        {
            return _tag;
        }
        
        public function set enabled(value:Boolean):void
        {
            _enabled = value;
            mouseEnabled = mouseChildren = _enabled;
            tabEnabled = value;
            alpha = _enabled ? 1.0 : 0.5;
        }

        public function get enabled():Boolean
        {
            return _enabled;
        }
        
        public function close():void
        {
            if(this.parent != null)
            {
                this.parent.removeChild(this);
            }
            
            if(this.maskCanvas != null)
            {
                this.maskCanvas.close();
            }
            this.dispatchEvent(new Event("closed"));
        }
        
        public function callLater(callback:Function):void
        {
            new CallLaterHelper(this.stage,callback);
        }
    }
}

package orc.common
{
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.display.Shape;
    import flash.events.Event;
    import flash.geom.Point;
    
    [DefaultProperty( "children" )]
    [Bindable]
    [Event(name="inited", type="flash.events.Event")] 
    public class BaseContainer extends BaseComponent
    {
        private var _children:Vector.<DisplayObject>;
        private var childrenChanged:Boolean = false;
        
        protected var inited:Boolean = false;
        
        protected function s(key:String,defaultValue:String = null):String
        {
            return l.i.getString(key,defaultValue);
        }
        
        /**
         * Array of DisplayObject instances to be added as children
         
*/
        public function get children():Vector.<DisplayObject>
        {
            return this._children;
        }
        
        public function set children( value:Vector.<DisplayObject> ):void
        {
            if ( _children != value )
            {
                if(_children != null)
                {
                    for each(var item:DisplayObject in value)
                    {
                        _children.push(item);
                    }
                }
                else
                {
                    _children = value;
                }
                childrenChanged = true;
                invalidate();
            }
        }
        
        public function BaseContainer(parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number =  0)
        {
            super(parent, xpos, ypos);
        }
        
        override protected function onInvalidate(event:Event) : void
        {
            if ( childrenChanged )
            {
                while ( numChildren > 0 )
                {
                    removeChildAt( 0 );
                }
                
                if(children != null)
                {
                    for each ( var child:DisplayObject in children )
                    {
                        addChild( child );
                    }
                }
                
                childrenChanged = false;
            }
            
            if(this.mask != null)
            {
                if(this.contains(this.mask))
                {
                    this.removeChild(this.mask);
                }
            }
            
            super.onInvalidate(event);
            
            if(inited == false)
            {
                inited = true;
                this.dispatchEvent(new Event("inited"));
            }
        }
        
        public function removeAllChildren():void
        {
            while(this.numChildren > 0)
            {
                this.removeChildAt(0);
            }
            
            if(this._children != null)
            {
                this._children = null;
                childrenChanged = true;
            }
        }
        
        public function setCenter(obj:DisplayObject):void
        {
            obj.x = 0.5 * (this.width - obj.width);
            obj.y = 0.5 * (this.height - obj.height);
        }
    }
}

 

  几个Helper类代码:

View Code
package orc.utils
{
    import flash.display.Stage;
    import flash.events.Event;

    public class CallLaterHelper
    {
        public function CallLaterHelper(stage:Stage, callback:Function)
        {
            this.callback = callback;
            this.stage = stage;

            stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame);
        }
        
        private var stage:Stage;
        
        private var callback:Function;
        
        private function onStageEnterFrame(event:Event):void
        {
            stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame);
            
            if(callback != null)
            {
                callback();
            }
        }
    }
}

package orc.utils
{
    public class MouseHelper
    {
        private var _stickHelper:MouseStickHelper;

        public function get stickHelper():MouseStickHelper
        {
            if(_stickHelper == null) _stickHelper = new MouseStickHelper();
            return _stickHelper;
        }
    }
}

package orc.utils
{
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.utils.Timer;

    public class MouseStickHelper
    {
        private var target:Sprite;
        private var timer:Timer = new Timer(intervalMiniSeconds);
        private var active:Boolean = false;
        private var mouseEvent:MouseEvent;
        
        private var _intervalMiniSeconds:uint = 100;

        public function get intervalMiniSeconds():uint
        {
            return _intervalMiniSeconds;
        }

        public function set intervalMiniSeconds(value:uint):void
        {
            _intervalMiniSeconds = value;
            timer.delay = value;
        }
        
        public var callback:Function = null;
        
        public function bind(obj:Sprite):void
        {
            unbind();
            target = obj;
            if(target != null)
            {
                target.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
                target.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
                target.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
                target.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }
        }
        
        public function unbind():void
        {
            if(target != null)
            {
                target.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
                target.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
                target.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
                target.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
                target = null;
                reset();
            }
        }
        
        private function onMouseDown(event:MouseEvent):void
        {
            active = true;
            timer.stop();
            if(timer.hasEventListener(TimerEvent.TIMER) == false)
            {
                timer.addEventListener(TimerEvent.TIMER, 
                    function(e:*):void
                    {
                        fireEvent();
                    }
                );
            }
            timer.start();
            fireEvent();
        }
        
        private function fireEvent():void
        {
            if(this.callback != null)
            {
                this.callback();
            }
        }
        
        private function onMouseMove(event:MouseEvent):void
        {
            if(active == falsereturn;
        }

        private function onMouseOut(event:MouseEvent):void
        {
            reset();
        }

        private function onMouseUp(event:MouseEvent):void
        {
            reset();
        }

        private function reset():void
        {
            active = false;
            timer.stop();
        }
    }
}

 

  下面开始搭积木。先是Shape。只要有背景的地方,都有Shape。下面是Shape的基类:

View Code
package orc.shapes
{
    import flash.display.BitmapData;
    
    import orc.common.BaseComponent;

    public class BaseShape extends BaseComponent
    {
        private var _color:uint = 0xFFFFFF;
        
        public function get color():uint
        {
            return _color;
        }
        
        public function set color(value:uint):void
        {
            if(_color == value) return;
            
            _color = value;
            this.invalidate();
        }
        
        private var _fillAlpha:Number = 1;
        
        public function get fillAlpha():Number
        {
            return _fillAlpha;
        }
        
        public function set fillAlpha(value:Number):void
        {
            _fillAlpha = value;
            this.invalidate();
        }

        private var _texture:BitmapData;

        public function get texture():BitmapData
        {
            return _texture;
        }

        public function set texture(value:BitmapData):void
        {
            _texture = value;
            this.invalidate();
        }
        
        private var _borderAlpha:Number = 1;
        
        
        public function get borderAlpha():Number
        {
            return _borderAlpha;
        }
        
        public function set borderAlpha(value:Number):void
        {
            _borderAlpha = value;
            this.invalidate();
        }
        
        private var _borderColor:uint;
        
        public function get borderColor():uint
        {
            return _borderColor;
        }
        
        public function set borderColor(value:uint):void
        {
            _borderColor = value;
            this.invalidate();
        }
        
        private var _borderThickness:Number = NaN;
        
        public function get borderThickness():Number
        {
            return _borderThickness;
        }
        
        public function set borderThickness(value:Number):void
        {
            _borderThickness = value;
            this.invalidate();
        }
        
        private var _descriptor:Descriptor;
        
        public function get descriptor():Descriptor
        {
            return _descriptor;
        }
        
        public function set descriptor(value:Descriptor):void
        {
            _descriptor = value;
            if(_descriptor != null)
            {
                _descriptor.resize(this);
            }
        }
    }
}

  BaseShape 继承了BaseComponent的x,y,width,height等属性,另外提供了填充色,填充透明度,纹理,边界色,边界透明度,边界厚度等属性。而又因为有些形状,比如圆,不方便用x,y,width,height等描述,更方便用圆心和半径描述,因此又提供了descriptor的属性。如,CircularDescriptor: 

View Code
package orc.shapes
{
    public class Descriptor
    {
        public function resize(shape:BaseShape):void
        {
            
        }
    }
}

package orc.shapes
{
    public class CircularDescriptor extends Descriptor
    {
        public var centerX:Number;
        public var centerY:Number;
        public var radius:Number;
        
        public function CircularDescriptor(centerX:Number,centerY:Number,radius:Number):void
        {
            this.centerX = centerX;
            this.centerY = centerY;
            this.radius = radius;
        }
        
        public override function resize(shape:BaseShape):void
        {
            shape.x = centerX - radius;
            shape.y = centerY - radius;
            shape.width = radius * 2;
            shape.height = radius * 2;
        }
    }
}

 

  接着是矩形控件: 

 

View Code
package orc.shapes
{
    import flash.display.Graphics;

    public class Rectangle extends BaseShape
    {
        private var _corner:Number = NaN;

        public function get corner():Number
        {
            return _corner;
        }

        public function set corner(value:Number):void
        {
            _corner = value;
            this.invalidate();
        }

        private var _corners:Array = null;
        
        public function get corners():Array
        {
            return _corners;
        }

        public function set corners(value:Array):void
        {
            _corners = value;
            this.invalidate();
        }

        public override function draw():void
        {
            var g:Graphics = this.graphics;
            g.clear();
            if(width > 0 && height > 0)
            {
                var c0:Number = corner;
                var c1:Number = corner;
                var c2:Number = corner;
                var c3:Number = corner;
                
                var c:Array = this.corners;
                if(c != null && c.length == 4)
                {
                    c0 = Number(c[0]);
                    c1 = Number(c[1]);
                    c2 = Number(c[2]);
                    c3 = Number(c[3]);
                }
                
                if(isNaN(c0)) c0 = 0;
                if(isNaN(c1)) c1 = 0;
                if(isNaN(c2)) c2 = 0;
                if(isNaN(c3)) c3 = 0;
                
                if(isNaN(borderThickness) == false && borderThickness > 0)
                {
                    g.lineStyle(this.borderThickness, this.borderColor, this.borderAlpha,true);
                }
                if(this.texture)
                {
                    g.beginBitmapFill(this.texture);                    
                }
                else
                {
                    g.beginFill(color, this.fillAlpha);
                }
                if(c0 == 0 && c1 == 0 && c2 == 0 && c3 == 0)
                {
                    g.drawRect(0,0,width,height);
                }
                else
                {
                    g.drawRoundRectComplex(0,0,width,height,c0,c1,c2,c3);
                }
                g.endFill();
            }
        }
    }
}

  

  这个矩形控件可以设置圆角。有了这个控件,各种各样的背景图就都可以实现了:有圆角的、没圆角的、有纹理的、有边界的,等等。

  椭圆/圆也经常用,写一个:

 

View Code
package orc.shapes
{
    import flash.display.Graphics;
    
    import orc.common.BaseComponent;

    public class Ellipse extends BaseShape
    {
        public override function draw():void
        {
            var g:Graphics = this.graphics;
            g.clear();
            if(width > 0 && height > 0)
            {
                if(isNaN(borderThickness) == false && borderThickness > 0)
                {
                    g.lineStyle(this.borderThickness, this.borderColor, this.borderAlpha);
                }
                
                if(this.texture)
                {
                    g.beginBitmapFill(this.texture);                    
                }
                else
                {
                    g.beginFill(color, this.fillAlpha);
                }
                g.drawEllipse(0,0,width,height);
                g.endFill();
            }
            
            super.draw();
        }
    }
}

 

  下面,我们建立一个简单的Canvas类,这个Canvas类可以设置背景,可以设置边界(背景和边界是用上面的Rectangle 类实现的。

 

View Code
<?xml version="1.0" encoding="utf-8"?>
<common:BaseContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                      xmlns:mx="library://ns.adobe.com/flex/mx"
                      xmlns:common="orc.common.*"
                      width="400" height="300" 
                      xmlns:controls="orc.controls.*"
                      xmlns:shapes="orc.shapes.*"
                      >
    <fx:Script>
        <![CDATA[
            [Bindable] 
            public var bgColor:uint = 0xFFFFFF;
            
            [Bindable]
            public var bgCorner:Number = NaN;
            
            [Bindable]
            public var bgCorners:Array = null;
            
            [Bindable]
            public var bgAlpha:Number = 1;
            
            [Bindable]
            public var bgEnabled:Boolean = true;
            
            [Bindable]
            public var bgBorderThickness:Number = NaN;
            
            [Bindable]
            public var bgBorderColor:Number = 0xFFFFFF;
            
            [Bindable]
            public var bgFillAlpha:Number = 1;
            
            [Bindable]
            public var bgBorderAlpha:Number = 1;
            
        ]]>
    </fx:Script>
    <shapes:Rectangle id="background" width="{width}" height="{height}"
                       corner="{bgCorner}" corners="{bgCorners}"
                       color="{bgColor}"
                       alpha="{bgEnabled?bgAlpha:bgAlpha*0.3}"
                       borderColor="{bgBorderColor}"
                       borderThickness="{bgBorderThickness}"
                       fillAlpha="{bgFillAlpha}" borderAlpha="{bgBorderAlpha}"
                       />
</common:BaseContainer>

 

  一个Canvas就是这么简单!下面,建立Image控件,这个Image支持九宫格(如果不知道九宫格,请Google之)

 

View Code
package orc.controls
{
    import flash.display.AVM1Movie;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.geom.Rectangle;
    import flash.net.URLRequest;
    
    import orc.common.Avm1Loader;
    import orc.common.BaseComponent;
    import orc.common.ScaleBitmap;
    
    [Event(name="complete",type="flash.events.Event")]
    public class Image extends BaseComponent
    {
        public static const MODE_9GRID:String = "9grid";
        
        private var _source:*;

        public function get source():*
        {
            return _source;
        }

        [Bindable]
        public function set source(value:*):void
        {
            _source = value;
            this.onInvalidate(null);
        }
        
        [Bindable]
        public var sourceScale9Grid:Rectangle;
        
        public var mode:String = MODE_9GRID;
        
        public function Image():void
        {
            super();
        }
        
        public override function draw():void
        {
            super.draw();
            if(source)
            {
                if(source is BitmapData)
                {
                    drawBitmapData(source);
                }
                else if(source is Bitmap)
                {
                    drawBitmapData(Bitmap(source).bitmapData);
                }
                else if(source is Class)
                {
                    var bmp:Bitmap = new source() as Bitmap;
                    if(bmp != null)
                    {
                        drawBitmapData(bmp.bitmapData);
                    }
                }
                else if(source is String)
                {
                    if(_loader != null)
                    {
                        _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loadCompleted);
                    }
                    
                    _loader = new Loader();
                    _loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadCompleted);
                    _loader.load(new URLRequest(source));
                }
            }
            else
            {
                clear();
            }
        }
        
        private function loadCompleted(e:Event):void
        {
            clear();
            
            var d:DisplayObject = _loader.content;
            var child:DisplayObject = d;
            if(d is AVM1Movie)
            {
                var bmpData:BitmapData = new BitmapData(d.width,d.height,true,0);
                bmpData.draw(d);
                child = new Bitmap(bmpData,"auto",true);
            }
            else if(d is Bitmap)
            {
                Bitmap(d).smoothing = true;
            }
            
            if(this.width > 0 && this.height > 0)
            {
                var xx:Number = this.width / child.width;
                var yy:Number = this.height / child.height;
                var scale:Number = Math.min(xx,yy);
                child.scaleX = scale;
                child.scaleY = scale;
            }
            else
            {
                this._width = child.width;
                this._height = child.height;
                this.dispatchEvent(new Event(Event.RESIZE));
            }
            this._bgBitmap = child;
            addChild(child);
            this.dispatchEvent(new Event(Event.COMPLETE));
        }
        
        private var _loader:Loader;
        
        private var _bgBitmap:DisplayObject = null;
        
        private function clear():void
        {
            if(_bgBitmap != null)
            {
                this.removeChild(_bgBitmap);
                _bgBitmap = null;
            }
        }
        
        protected function drawBitmapData(bmpData:BitmapData):void
        {
            clear();
            
            if(bmpData == nullreturn;
            
            if(this.width == 0 || this.height == 0)
            {
                this._width = bmpData.width;
                this._height = bmpData.height;
                this.dispatchEvent(new Event(Event.RESIZE));
            }
            
            var sb:ScaleBitmap = new ScaleBitmap(bmpData,"auto",true);
            sb.scale9Grid = this.sourceScale9Grid;
            sb.setSize(this.width,this.height);
            _bgBitmap = sb;
            this.addChild(sb);
            this.dispatchEvent(new Event(Event.COMPLETE));
        }
        
        public function getBitmap():Bitmap
        {
            if(this._bgBitmap == nullreturn null;
            var bmpData:BitmapData = new BitmapData(this._bgBitmap.width,this._bgBitmap.height, true0);
            bmpData.draw(this._bgBitmap, new Matrix(this._bgBitmap.scaleX,0,0,this._bgBitmap.scaleY));
            var bmp:Bitmap = new Bitmap(bmpData);
            return bmp;
        }
    }
}

 

  那么,我们如何让CanvasBaseContainer中显示背景图呢?简单,在里面放个Image控件即可,比如,这是我写的ImageButton控件:

 

View Code
<common:BaseContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   xmlns:oc="orc.controls.*"
                   xmlns:common="orc.common.*"
                   buttonMode="true" useHandCursor="true"
                   mouseChildren="{enable}" mouseEnabled="{enable}"
                   mouseOver="{if(enable == true) alpha=0.6;}"
                   mouseOut="{if(enable == true) alpha=1;}" 
                   >
    <fx:Script>
        <![CDATA[
            [Bindable]
            public var source:*;
            
            public function get enable():Boolean
            {
                return img ? img.enabled : true;
            }

            [Bindable]
            public function set enable(value:Boolean):void
            {
                img.enabled = value;
                if(value == true) alpha = 1;
            }
        ]]>
    </fx:Script>
    <oc:Image id="img" source="{source}" mouseChildren="false" mouseEnabled="false" />
</common:BaseContainer>

 

  Label控件离不了,恩,就在网上的一份代码基础上写个Label控件:

 

View Code
package orc.controls
{
    import flash.display.DisplayObjectContainer;
    import flash.events.Event;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    
    import orc.common.BaseComponent;
    import orc.common.Style;
    
    [Event(name="resize", type="flash.events.Event")]
    public class Label extends BaseComponent
    {
        protected var _autoSize:Boolean = false;
        protected var _text:String = "";
        protected var _tf:TextField;
        
        public var fontName:String = Style.fontName;
        public var fontSize:Number = Style.fontSize;
        public var fontColor:uint = 0x000000;
        public var align:String = "left";
        public var bold:Boolean = false;
        
        public function Label(parent:DisplayObjectContainer = null, xpos:Number = 0, ypos:Number =  0, text:String = "")
        {
            this.text = text;
            super(parent, xpos, ypos);
        }
        
        override protected function init():void
        {
            super.init();
            mouseEnabled = false;
            mouseChildren = false;
        }
        
        override protected function addChildren():void
        {
            _height = 18;
            _tf = new TextField();
            _tf.height = _height;
            _tf.selectable = false;
            _tf.mouseEnabled = false;
            _tf.text = _text;            
            addChild(_tf);
            draw();
        }
        
        override public function draw():void
        {
            super.draw();
            var f:TextFormat = new TextFormat(fontName,fontSize,fontColor);
            f.align = this.align;
            f.bold = this.bold;
            _tf.defaultTextFormat = f;
            _tf.text = _text;
            if(_autoSize)
            {
                _tf.autoSize = TextFieldAutoSize.LEFT;
                _width = _tf.width;
                dispatchEvent(new Event(Event.RESIZE));
            }
            else
            {
                _tf.autoSize = TextFieldAutoSize.NONE;
                _tf.width = _width;
            }
            _height = _tf.height = 18;
        }
        
        public function set text(t:String):void
        {
            _text = t;
            if(_text == null) _text = "";
            invalidate();
        }
        
        public function get text():String
        {
            return _text;
        }
        
        public function set autoSize(b:Boolean):void
        {
            _autoSize = b;
        }
        
        public function get autoSize():Boolean
        {
            return _autoSize;
        }
        
        public function get textField():TextField
        {
            return _tf;
        }
    }
}

 

  接下来Button控件呼之欲出:

 

View Code
<containers:Canvas xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   xmlns:common="orc.common.*"
                   xmlns:controls="controls.*"
                   xmlns:oc="orc.controls.*"
                   xmlns:containers="orc.containers.*"
                   width="120" height="24"
                   bgColor="{isMouseOver?mouseOverColor:defaultColor}"
                   bgCorner="6"
                   buttonMode="true" useHandCursor="true"
                   mouseOver="{isMouseOver = true}"
                   mouseOut="{isMouseOver = false}"
                   >
    <fx:Script>
        <![CDATA[
            [Bindable]
            public var label:String = "";
            
            [Bindable]
            public var labelHeight:Number = 20;
            
            [Bindable]
            public var defaultColor:uint = 0xCCCCCC;
            
            [Bindable]
            public var mouseOverColor:uint = 0xDDDDDD;
            
            [Bindable]
            public var isMouseOver:Boolean = false;
        ]]>
    </fx:Script>
    <oc:Label id="lbLabel" text="{label}" width="{width}" y="{0.5*(height-labelHeight)}"
              mouseEnabled="false" height="{labelHeight}" fontSize="12" align="center"
              />
</containers:Canvas>

 

  进度条Progress就太容易了:

 

View Code
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   xmlns:common="orc.common.*"
                   xmlns:controls="orc.controls.*"
                   xmlns:containers="orc.containers.*" 
                   xmlns:shapes="orc.shapes.*" 
                   bgBorderThickness="1" bgColor="0xFFFFFF" bgBorderColor="0x333333" 
                   width="200" height="20" 
                   >
    <fx:Script>
        <![CDATA[
            [Bindable]
            public var percent:Number = 0;
            
            [Bindable]
            public var fillColor:uint = 0x0000FF;
            
            private function getWidth(val:Number):Number
            {
                var ww:Number = this.width - 2;
                return ww * val;
            }
        ]]>
    </fx:Script>
    <shapes:Rectangle x="1" y="1" color="{fillColor}" height="{height-2}" width="{getWidth(percent)}" />
</containers:Canvas>

 

  定位?容易!有数据绑定,想让它在哪里就在哪里,如:

 

x="{0.5*width-borderThickness*0.5}" y="{-handleLength}"

 

  带图标的按钮ComboButton

 

 

View Code
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:mx="library://ns.adobe.com/flex/mx" 
           xmlns:containers="orc.containers.*"
           xmlns:controls="orc.controls.*"
           mouseChildren="false" 
           bgCorner="5"
           buttonMode="true" useHandCursor="true"
           mouseOver="{alpha=0.9;}"
           mouseOut="{alpha=1;}" 
           width="200" height="50"
           >
    <fx:Script>
        <![CDATA[
            [Bindable]
            public var source:Class;
            
            [Bindable]
            public var label:String;
        ]]>
    </fx:Script>
    <controls:Image x="30" y="10" source="{source}" />
    <controls:Label x="70" y="18"
                    text="{label}" 
                    fontSize="12" 
                    width="120"
                    />
</containers:Canvas>

 

  HSlider: 

 

 

View Code
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:mx="library://ns.adobe.com/flex/mx"
                   xmlns:common="orc.common.*"
                   xmlns:controls="controls.*"
                   xmlns:containers="orc.containers.*"
                   xmlns:shapes="orc.shapes.*"
                   width="264" height="22"
                   bgAlpha="0"
                   inited="onInited()"
                   >
    <fx:Metadata>
        [Event(name="drag",type="flash.events.Event")]
    </fx:Metadata>
    <fx:Script>
        <![CDATA[
            import orc.events.MoveEvent;
            import orc.utils.DragHelper;
            
            [Bindable]
            public var maximum:Number = 3;
            [Bindable]
            public var minimum:Number = 0;
            [Bindable]
            public var value:Number = minimum;
            
            private var dragHelper:DragHelper = new DragHelper();
            
            private function get minX():Number
            {
                return 0;
            }
            
            private function get maxX():Number
            {
                return this.width - btnDrag.width + 1;
            }
            
            private function checkX(val:Number):Number
            {
                val = Math.max(val,minX);
                val = Math.min(val,maxX);
                return val;
            }
            
            private function checkValue(val:Number):Number
            {
                val = Math.max(val,minimum);
                val = Math.min(val,maximum);
                return val;
            }
            
            private function getX(val:Number, min:Number = NaN, max:Number = NaN):Number
            {
                val = this.checkValue(val);
                return minX + (maxX - minX) * (val - minimum ) / (maximum - minimum);
            }
            
            private function onInited():void
            {
                dragHelper.bind(btnDrag, this);
                dragHelper.addEventListener(MoveEvent.MOVING, onDrag);
            }
            
            private function onDrag(event:MoveEvent):void
            {
                var xx:Number = checkX(event.xOffSet/this.scaleX + btnDrag.x);
                dragToX(xx);
            }
            
            private function dragToX(val:Number):void
            {
                this.value = convertX2Value(val);
                this.dispatchEvent(new Event("drag"));                
            }
            
            private function convertX2Value(x:Number):Number
            {
                var val:Number = minimum + (maximum - minimum) * (x - minX ) / (maxX - minX);
                return checkValue(val);
            }
            
            private function onMouseStick(e:Event):void
            {
                var step:Number = 5;
                var xx:Number = this.btnDrag.x;
                if(this.btnDrag.mouseX > 0)
                {
                    xx += step;
                }
                else
                {
                    xx -= step;
                }
                
                dragToX(xx);
            }
        ]]>
    </fx:Script>
    <controls:ImageButton y="1.4"
                          width="264" height="22"
                          enableMouseStick="true"
                          mouseStick="onMouseStick(event)"
                          mouseStickIntervalMiniSeconds="40"
                          source="@Embed(source='assets/hsliderBg.png')"
                          />
    <controls:ImageButton source="@Embed(source='assets/slider.png')"
                          id="btnDrag"  x="{getX(value, minimum, maximum)}" 
                          width="25" height="25" />
</containers:Canvas>

 

  图像拉伸、旋转、缩放、删除的控制框控件复杂一点,400多行,代码贴时出错了,就不贴了,效果图:

 

 

  当然,滚动条啥的控件就复杂一点,不想写可以就拿Flash里自带的包装一下,照样用。

  然后是动画,动画也很容易,下面是让一个界面慢慢的变小的代码:

 

View Code
            [Bindable]
            public var centerX:Number = 0;
            
            [Bindable]
            public var centerY:Number = 0;
            
            [Bindable]
            public var targetWinth:Number = 0;
            
            [Bindable]
            public var targetHeight:Number = 0;
            
            private var _percent:Number = 0;
            
            public function get percent():Number
            {
                return _percent;
            }
            
            [Bindable]
            public function set percent(value:Number):void
            {
                if(value == 1) cvs.visible = true;
                else if(cvs.visible == true) cvs.visible = false;
                
                _percent = value;
                this.width = targetWinth * value;
                this.height = targetHeight * value;
                this.callLater(
                    function():void
                    {
                        x = centerX - width * 0.5;
                        y = centerY - height * 0.5;
                    });
            }
            
            public function min():void
            {
                TweenLite.to(this,0.5,{percent:0});
            }

 

  看看我做的一个项目的整体效果图,这些界面大部分都是从Draw API一步步绘制的:

 

   as3有个叫haXe的兄弟语言,haXe写的代码可以在Flash平台运行,可以在js环境运行,铺平了向html5的过渡之途。

下面,回答前面提出的四个问题:我会哪些?我学了哪些?我能做什么?做这些我相对于别人有哪些优势?

我会哪些?我学了哪些?

Flash CS系列工具会吗?不会!

Flex会吗,会一点点而已。

还就只懂几个API和数据绑定和几个Flash基本类。其实这就够了。有基本类、有几个API,有数据绑定,组合起来就是非常强大的工具,我们不需要学习多少东西,却可以非常高效率的开发很多应用,且开发的这些应用可以分发到各大平台。不需要学习多少控件,有学习的时间,就够写一个自己的了。自己写的控件没有冗余,性能高,编译后的尺寸小,且修改方便。

我能做什么?

通常的,对特效要求不是特别高的Flash App都能做,这意味着,某些桌面软件,某些Web应用,某些ios应用和某些android应用。额,Html5也算顺便能做,今年顺手用haXe做了个html5的项目。

我相对于别人有哪些优势?

那些用Flash CS开发的,开发效率低,代码可维护性差。那些用Flex开发的,代码尺寸大,程序性能差。俺这样的优势就是Flex般的开发效率和灵活性,Flash般的性能和代码尺寸,且什么都是自己写的,出了问题自己也好弄,不像Flex那样是代码迷宫。

学的少,可做的多,相对别人还有优势,这是不是就是遁去的一呢?要是按照书本学,按照别人的建议学,东西学了一大堆,能做多少还是个问题,能以什么效率做也是个问题,更可怕的是,学完了还不知道自己学习的是什么。

只学一点点,不累!剩下的,交给狗爹度娘吧。

  注:本文代码只有主要代码,那些不影响阅读的代码就没贴出来,不然太长了。又由于和业务代码在一个项目里,也不方便打包放出。见谅!

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
posted @ 2011-12-10 16:23 xiaotie 阅读(8037) 评论(64) 编辑 收藏

 回复 引用 查看   
#1楼 2011-12-10 16:49 devil0153      
偶像发新文,严重同意你的观点,另外,精通真的很宽泛,你觉得精通,碰到一个高手就觉得自己差得远了,所以,技术是为需求服务的,技术只是工具,生命是有限的,我们不能浪费生命在工具本身上,而应该专注于使用工具创造价值上!
 回复 引用 查看   
#2楼 2011-12-10 17:16 怒吼!!!      
不错,跟我的经历有点像
 回复 引用 查看   
#3楼 2011-12-10 18:02 路过秋天      
flash离有我点远,不过看图片,挺漂亮的,赞一个。
 回复 引用 查看   
#4楼 2011-12-10 18:31 王一一      
铁哥出本书吧
 回复 引用 查看   
#5楼 2011-12-10 18:57 撞破南墙      
solo必备,铁哥说明下适用条件环境
 回复 引用 查看   
#6楼[楼主] 2011-12-10 19:06 xiaotie      
@王一一
积累还不够
@撞破南墙
应用太复杂的不适合。数据类应用不适合。

 回复 引用 查看   
#7楼 2011-12-10 19:16 pandaren      
lz说的 黄易的大唐双龙传 中的说法简直就是赤裸裸的抄袭啊....
 回复 引用 查看   
#8楼 2011-12-10 19:47 syx278250658      
lz已达到另一种境界了
很强大,顶一下。
 回复 引用 查看   
#10楼 2011-12-10 21:32 卤水兄      
境界
 回复 引用 查看   
#11楼 2011-12-10 23:00 Lumj      
今天才发现'GEB'和' 集异璧'是谐音-_-!
 回复 引用 查看   
#12楼 2011-12-11 02:04 程子清      
支持
 回复 引用 查看   
#13楼 2011-12-11 10:29 Eugene Wang      
楼主的境界好高,赞一个
 回复 引用 查看   
#14楼 2011-12-11 12:22 zjyuan      
有道理,学习了
 回复 引用 查看   
#15楼 2011-12-11 13:25 小毛驴      
上善若水,以少替多。五体投地,佩服下
 回复 引用 查看   
#16楼 2011-12-11 14:38 在别处      
学习就当这样
 回复 引用 查看   
#17楼 2011-12-11 15:24 SongSharp      
这个一点点是指,项目需要用到的那一点。
但为了知道这一点点而不是别的一点点,就需要许多的知识点点组成出来的。遁去的一这个境界如果没有经历过2,3,4又如何到一
本人境界不到,实在不敢一点点呀!
不积小流无以成江河,就像当我们度娘的时候用的还是别人开发好的搜索算法。说到底我们还是用别人开发的轮子在跑。
知识就是知道与不知道,用到的那点点知道了,加上一堆if else,while就成了。

 回复 引用 查看   
#18楼[楼主] 2011-12-11 19:00 xiaotie      
@SongSharp
不增加心智负担,用用别人的轮子没什么。本文只是方法的一种,每个人都有最适合自己的方法。为技术把自己搞的累死累活的就没意思了。要能分辨某个东西对自己的价值。玩技术而不是被技术玩。

 回复 引用 查看   
#19楼[楼主] 2011-12-11 19:23 xiaotie      
@SongSharp
这个一点点需要的是发现,不是学,不是知道。没人告诉你什么对你是最适合的。不要敬畏知识,知识是不断批判和否定得来的。并且现在知识都分得很细,越细越具体。而对于抽象性的整体性的研究,人们并没有比古人进步多少。而我们的项目,是整体性的。产品,是整体性的。人是整体性的。不是单纯的if else或tradeoff能处理的。不说别的,单说取舍都很艰难。我就是在不断批判WPF/SL中进步的。WPF/SL可谓知识云集,单绑定就能说完书的一章,各种花式花样的绑定都有。依赖属性又可以说一章。Flash这边,数据绑定就是个语法糖,一页纸就说完了,而依赖属性啥的根本不存在,几乎没有“知识”。我就是强烈抗拒WPF/SL的数据绑定,才不断的在探索Flash的数据绑定能做多少事情,结果出乎意外,几乎什么都能做,做的还蛮不错的。这样一来,我就不用学习什么,就够用了。

 回复 引用 查看   
#20楼 2011-12-11 19:24 青蛙王子。      
俺 还没找到自己遁去的一///LZ说的遁去的一就是专一的意思....自己喜欢的一项技术就是了(这个技术在你看来是要非常强大的/并且能够为你制造金钱也就是工资的技术)
 回复 引用 查看   
#21楼[楼主] 2011-12-11 19:25 xiaotie      
@Lumj
G-哥德尔;E-艾舍尔;B-巴赫。把GEB翻译成集异璧是老翻译家们的妙笔。

 回复 引用 查看   
#22楼[楼主] 2011-12-11 19:29 xiaotie      
@青蛙王子。
:P 慢慢找 还有大半辈子呢

 回复 引用 查看   
#23楼 2011-12-11 21:23 Si Seulemen      
恩……认同!我一直觉得程序就跟现实生活中没什么两样,关键是解决问题的能力,知道有这个东西,等到用的时候再去快速查看帮助文档,这样可以培养自己快速解决问题的能力。
 回复 引用 查看   
#24楼 2011-12-11 22:04 茫茫深海一条鱼      
看这篇文章的时候没看作者名称,但看着看着就想起了xiaotie哥,赶紧来到篇末一看,果然是xiaotie哥,哈哈
 回复 引用 查看   
#25楼 2011-12-11 22:30 Virson Ma      
很赞成,能做出来才是真的,:-)
 回复 引用 查看   
#26楼 2011-12-11 23:12 JasenKin      
顶下铁哥!
每个领域都是个无底洞,而人的生命和时间是有限的,主要还是取决于学习能力了,对于任何未知的东西,即学即用就可以了。

 回复 引用 查看   
#27楼 2011-12-12 08:32 BruceWu      
一看文章就是铁哥的风格,再看地址果然是,果断读完
 回复 引用 查看   
#28楼 2011-12-12 08:36 喔、勒勒      
好犀利呀
 回复 引用 查看   
#29楼 2011-12-12 08:59 不觉流年似水      
用到的这个“一”,背后需要很多知识点作支撑;试想你去跟一个不懂Flash开发的人直接讲重点,他是不会懂的。
楼主的方法学只有达到一定经验后才有效,呵呵.

 回复 引用 查看   
#30楼 2011-12-12 09:05 冰の酷龙      
支持铁哥~~只是一般人还得受技术折磨~
 回复 引用 查看   
#31楼 2011-12-12 09:22 gws      
楼主,我想问下,你用GDI+开发的图形界面都应用于什么项目?我觉得现在。NET开放的客户端项目很少了吧。而且如果是大量客户使用的项目,用指针开放GDI+出问题的概率高不。
 回复 引用 查看   
#32楼 2011-12-12 09:30 yangjun      
顶李敖和铁哥的文章,高中时大爱李敖,现在有点愤青过头了。

as3和as2差这么远吗?还好,我从来没有接触过,现在有个项目里面需要三维导航,很简单的功能,因为项目组没有人会,总是要外包,看了你这个文章,干脆就用as3改写一下,谢谢文章指导。

 回复 引用 查看   
#33楼 2011-12-12 09:30 天外来客之火星人      
文笔不错
 回复 引用 查看   
#34楼[楼主] 2011-12-12 09:35 xiaotie      
@gws
用GDI+开发只是个比喻,我现在操作图像都是自己写的unsafe代码(画线啊,画圆啊自己还没写,暂时用的还是GDI+)。用.net开发的客户端项目还是不少的(和Web比起来算少,但绝对数量不少)。我个人感觉:遵循dispose模式的话,.net下大用指针的话不容易出错。而又只有部分需要高性能的代码要用指针,不像C/C++那样普遍的用指针,出错概率又小了很多。加上.net下好调试,好重构,代码优雅,开发速度很高。界面的话用WPF或Winform,是很有生产力的一种技术安排。

 回复 引用 查看   
#35楼[楼主] 2011-12-12 09:40 xiaotie      
@yangjun
不懂as2 :P

 回复 引用 查看   
#36楼[楼主] 2011-12-12 09:45 xiaotie      
Flash的例子演示了只用简单的API,经过数据绑定增强后,可以很方便的做很多事情。不限于Flash,这些API,Windows下也有,html5下也有,但是,在这两个平台下,却没有对应的数据绑定。WPF/SL的数据绑定太复杂了,缺乏灵活,实现这样的过程比较痛苦。因此需要去寻找/发现或者自己编写类似的数据绑定机制,释放出生产力。
 回复 引用 查看   
#37楼 2011-12-12 10:34 玉开      
楼主很生猛,佩服
 回复 引用 查看   
#38楼 2011-12-12 11:17 Jeffrey Zhao      
你这个“不学”,是基于之前已经学过很多,能自己从简单的东西用出花来的那种,哈哈。
 回复 引用 查看   
#39楼 2011-12-12 11:36 木野狐(Neil Chen)      
没有完整的看过大唐双龙传,但对你的观点心有戚戚焉。铁哥的“遁去的一”来之不易啊~
最近也在反思如何将各种技术融会贯通。想起三国演义里孔明说的
“若夫小人之儒,惟务雕虫,专工翰墨,青春作赋,皓首穷经;笔下虽有千言,胸中实无一策。”
做技术的人,千万不能做专事雕虫的小人之儒,快速学以致用,有所创新才算真本事。

 回复 引用 查看   
#40楼[楼主] 2011-12-12 11:54 xiaotie      
@木野狐(Neil Chen)
专事雕虫的也是需要的,不然碰到技术问题了,一google全是我这样的扯蛋文章,也没用。本文另一个目的就是推广Flex的数据绑定,尽快推广到别的领域去,比如,C,C++,WPF/SL,Html,在我看来,这种数据绑定实在是优美极了,值得推广。我不懂编译原理,这种事情自己做不来。唯有写博客,等待有缘人。可我如果取个带Flash的博客标题,没几个人看啊。

 回复 引用 查看   
#41楼 2011-12-12 13:37 gooliugle      
@王一一
出书。

 回复 引用 查看   
#42楼 2011-12-12 13:38 gooliugle      
不错。
 回复 引用 查看   
#43楼 2011-12-12 13:52 追逐什么      
你手yin太多
 回复 引用 查看   
#44楼 2011-12-12 14:13 Seven07      
o(︶︿︶)o ,楼主说得很轻巧啊,你说的一点点的前提必须是丰富的经验和基础吧?
 回复 引用 查看   
#45楼 2011-12-12 14:13 深邃的狮子座      
@xiaotie
我被你这招骗了。

 回复 引用 查看   
#46楼 2011-12-12 14:20 Loro      
引用Jeffrey Zhao:你这个“不学”,是基于之前已经学过很多,能自己从简单的东西用出花来的那种,哈哈。

确实是,楼主已经做到手中无剑,心中有剑了,以无招胜有招。
楼主已经是另一种境界了。。。

 回复 引用 查看   
#47楼 2011-12-12 14:57 零 、一      
赞同44楼,当然楼主很好,台上一分钟台下十年功,只有拥有扎实的基础才能这样这样一点点的去学,否则只能学个不伦不类,楼主应该把前提补充一下,免得误人子弟,如楼主说、从事的图像 视频处理,这里的指针和多线程的一点点的 恐怕不是一点点吧,厚积薄发我个人觉得更准确
 回复 引用 查看   
#48楼 2011-12-12 15:01 undefined      
万事万物皆为攻受

呃, 为什么。。。。。
为什么。。。。。。。。。。。。。。。。

 回复 引用 查看   
#49楼 2011-12-12 16:23 阿祖      
仰望楼主
 回复 引用 查看   
#50楼 2011-12-12 17:12 貓崽      
这诗貌似出自李敖的一本黄书《上山上山爱》
 回复 引用 查看   
#51楼 2011-12-12 17:35 testzhangsan      
铁哥适合当老板,鉴定完毕!
 回复 引用 查看   
#52楼 2011-12-12 17:35 know@more      
师傅,文章写的诙谐通俗,so good,flex的代码看起来比较优雅,呵呵...
 回复 引用 查看   
#53楼 2011-12-12 18:53 SongSharp      
@xiaotie
有时候也奇怪,微软的之前的技术都在追求拖拖拉拉,易学易用,傻瓜化编程。但发现越到后来的东西就越来越复杂。winfrom到wpf已经是两个世界。其实大哥你说的对,简单好用的东西就应该推广开来。微软是一个很会模仿的公司,难保不久后出个wpf linq to xxx 绑定...呵呵

 回复 引用 查看   
#54楼 2011-12-12 20:27 roloxa      
什么情况 我只看了一点点
 回复 引用 查看   
#55楼 2011-12-12 23:39 alxc      
只适用已经编程好久,基础非常扎实的人,如果一个新手或者2、3年经验的人出去面试,谈这观点,80%会被pass吧。
 回复 引用 查看   
#56楼 2011-12-13 11:44 lovecd      
很好,关注中
 回复 引用 查看   
#57楼 2011-12-13 17:59 揉木而弦      
我希望中国那些有理想,有抱负,有创新的IT人才永远不要看到你这篇文章. 一个只习惯于使用别人东西的人才,永远只是肤浅,跟在别人屁股后头前进的人.
 回复 引用 查看   
#58楼 2011-12-14 14:39 云何去      
技术是来解决问题的,不是增加心智负担的。
---说得不错

 回复 引用 查看   
#59楼 2011-12-20 11:51 vanxining      
感觉这也是个人的一种选择吧。
就譬如考试,有些人喜欢把书中所有内容都细细地读一遍,有些人就是为了通过考试,只看老师画的重点,甚至连书都不看,只看PPT。
记得谁说过,一个VB程序员写C++程序,他的思维依然是VB,蜻蜓点水地用C++,有点像为生活所迫而用。
当然,只学一点点是可以做实事的,譬如一个C++程序员,几小时就可以用Java写程序,但他懂得Java什么呢?只懂得和C++一样的地方,而这些恰恰是最简单的那些……

 回复 引用 查看   
#60楼 2011-12-20 18:39 秋色      
对学习网页设计应该可以。但对于程序设计远远不足。
 回复 引用 查看   
#61楼 2012-01-03 07:19 野马007      
铁哥的话有道理,有些东西,其实可以边学边做,看似困难,其实只要做下去,就做成了。
 回复 引用 查看   
#62楼 2012-01-03 07:22 野马007      
顶铁哥的进攻式学习方法。
 回复 引用 查看   
#63楼 2012-01-06 19:04 眯妖      
看完了
 回复 引用 查看   
#64楼 2012-02-16 10:36 匹配度      
不懂,但思想说法 牛X啊。。。。