只学一点点:我的技术学习策略_极客玩家大白

转载自 只学一点点:我的技术学习策略 - xiaotie

by 极客玩家大白-xiaotie头像


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

不爱那么多,

只爱一点点;

别人的爱情像海深,

我的爱情浅。

不爱那么多,

只爱一点点;

别人的爱情像天长,

我的爱情短。

不爱那么多,

只爱一点点;

别人眉来又眼去,

我只偷看你一眼。

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

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

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

作为一个上个世纪就开始写网页的程序员,你如果问我这个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程序的第三个年头。俺,是一个不会Flash的Flash程序员。你如果让我用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) Getter和Setter分别为:function get foo():int; 和function set foo(i:int):int;

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

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

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

1
2
3
4
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搭建自己需要的控件。

数据绑定非常容易!

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

1
2
3
4
5
6
7
8
    <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的数据绑定简洁多了、易用多了。

下面,就靠这些开始征程。 先解决多语言的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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 == null) return;
            
            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代表取的是string。Xml文件中存储的是键值对,这样写: <Button label="{l.i.s('Yes')}" /> 就绑定了多语言,如果不加载任何语言文件的话,显示的是“Yes”,如果加载了的话,如果该文件中存在键“Yes”,则加载对应的值,如果不存在,则寻找是否有小写后为“yes”的键,加载对应的值,如果都不存在,则显示“Yes”。而当更改语言时,由于i发生了变化,由于数据绑定的关系,该Button的label值也马上得到了更新。 寥寥几行代码就实现了多语言解决方案。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
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, .3, 1, 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类代码


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 == false) return;
        }


        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的基类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
        }
    }
}

  接着是矩形控件: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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();
            }
        }
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 类实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="utf-8"?>
<common:BaseContainer xmlns:fx="[http://ns.adobe.com/mxml/2009](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之) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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 == null) return;
            
            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 == null) return null;
            var bmpData:BitmapData = new BitmapData(this._bgBitmap.width,this._bgBitmap.height, true, 0);
            bmpData.draw(this._bgBitmap, new Matrix(this._bgBitmap.scaleX,0,0,this._bgBitmap.scaleY));
            var bmp:Bitmap = new Bitmap(bmpData);
            return bmp;
        }
    }
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<common:BaseContainer xmlns:fx="[http://ns.adobe.com/mxml/2009](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控件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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控件呼之欲出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<containers:Canvas xmlns:fx="[http://ns.adobe.com/mxml/2009](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就太容易了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="[http://ns.adobe.com/mxml/2009](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>

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

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

带图标的按钮:

极客玩家大白-ComboButton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="[http://ns.adobe.com/mxml/2009](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: 

极客玩家大白-Slider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<?xml version="1.0" encoding="utf-8"?>
<containers:Canvas xmlns:fx="[http://ns.adobe.com/mxml/2009](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多行,代码贴时出错了,就不贴了,效果图:

极客玩家大白-resize box

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
            [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那样是代码迷宫。 学的少,可做的多,相对别人还有优势,这是不是就是遁去的一呢?要是按照书本学,按照别人的建议学,东西学了一大堆,能做多少还是个问题,能以什么效率做也是个问题,更可怕的是,学完了还不知道自己学习的是什么。 只学一点点,不累!

剩下的,交给狗爹度娘吧。

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

版权声明

  • 本文作者:极客玩家大白
  • 本文链接:https://yanglr.github.io/just-learn-little.html
  • 郑重声明:本文为博主原创或经授权转载的文章,欢迎转载,但转载文章之后必须在文章页面明显位置注明出处,否则保留追究法律责任的权利。如您有任何疑问或者授权方面的协商,请留言。


一个有故事的程序员

(转载本站文章请注明作者和出处 极客玩家大白

点击了解 :.NET技术人的网站


Show Disqus Comments

Post Directory