SlideShare a Scribd company logo
GHOST CAT
准备工作 创建工程 导入 Ghost Cat SWC 文件 创建资源 FLA 文件 asset.fla 创建多语言配置文件 ui.lang (可选)
asset.fla 内容如图所示 其中 upArrow,downArrow 元件位于 scrollBar 元件中, nameText,numText 位于 render 元件中。所示文字表示的是元件在场景中的示例名。 整个图形绑定了类名 asset.Panel (此外, tabBar 和 render 由于在之后会被复制,也绑定了类名 asset.TabBar,asset.Render ,但这个类名只是用于复制,代码中并不会出现,其实无论取什么名字都没有关系)
UI.lang 多语言并不是必须的,只是这个例子中包含了此特性。在之后的代码会会自动转换。 内容只有两行 name= 新的文字 title= 标题栏 在后面的代码中, @name 会被自动转换为“ 新的文字 ”, @title 会被自动转换为“ 标题栏 ”,将不再进行解释
建立文档类 public   class  test  extends  Sprite { public   function  test() { LanguageManager.instance.load( " ui.lang " ); // 加载多语言 AssetManager.instance.loadResource( " asset.swf " ); // 加载资源 Queue.defaultQueue.addEventListener(OperationEvent.OPERATION_COMPLETE,loadCompleteHandler);// 监听资源加载完成事件 } private   function  loadCompleteHandler(event:OperationEvent): void { stage.addChild(new ToolTipSprite());// 加入提示框 addChild( new   Panel ());// 显示 Panel 窗体 } }
Panel.as ( 效果 ) public   class  Panel  extends   GBuilderBase  // 继承此类便有拥有全部特性 { public   var  titleText:GText; public   var  mc:GMovieClip; public   var  tabBar:GButton; public   var  upArrow:GButton; public   var  downArrow:GButton; public   var  nameText:GText; public   var  numText:GText; public   function  Panel() { super ( " asset.Panel " ); // 连接资源 tabBar.data =  "A" ; nameText.text =  "@name" ; numText.text =  "A" ; mc.setLabel( null ,1); // 让动画只播放一次 } } 类名 asset.Panel 资源和类属性名称一一对应
Panel.as v2 ( 效果 ) public   class  Panel  extends  GBuilderBase { public   var  titleText:GText; public   var  mc:GMovieClip; public   var  tabBar:GButton; //public var upArrow:GButton; //public var downArrow:GButton; public   var   scrollBar :GHScrollBar; //public var nameText:GText; //public var numText:GText; public   var   render :GListBase; public   function  Panel() { super ( “asset.Panel” );// 仍然使用原来的资源 mc.setLabel( null ,1); // 让动画只播放一次 tabBar.data =  "GhostCat" ; render.type = UIConst.HORIZONTAL; // 设置 List 方向 render.itemRender =  Render ; // 设置 Render render.data = [ "G" , "H" , "O" , "S" , "T" , " " , "C" , "A" , "T" ]; scrollBar.setTarget(render,render.columnWidth * 2); // 指定滚动条 scrollBar.detra = render.columnWidth; // 指定滚动距离 new  ZoomEffect( this , null ,0.1,1000,{ease:Elastic.easeIn}, true ).execute();// 展开效果 } } 这里直接定义父层元件,滚动条的两个按钮自动声明,而 render 则在 Render.as 中定义 设置列表的伸展方向,渲染器 ( 见下页,内容,设置滚动区域,滚动速度 最后加入一个从中间展开的效果
Render.as public   class  Render  extends  GBuilderBase { public   var  nameText:GText; public   var  numText:GText; public   function  Render(skin:*= null , replace:Boolean= true ) { super (skin, replace);// 保持默认值,皮肤由外部传入 }   // 复写 data 的 set 方法来获得数据 public   override   function   set  data(v:*) :  void { super .data = v; nameText.text = numText.text = v; this .toolTip =  " 当前值: "  + v; TextFieldUtil.autoFontSize(numText.textField); // 调整字号使得可以全部显示 }   // 复写 selected 属性来设置选中效果 public   override   function   set  selected(v:Boolean) :  void { super .selected = v; this .transform.colorTransform = v ?  new  ColorTransform(1,1,1,1,50,50,50) :  new  ColorTransform(); } }
已经有基类,不能直接使用 GBuildBase? public   class  Render  extends  GButton { public   var  nameText:GText; public   var  numText:GText; public   function  Render(skin:*= null ,  replace:Boolean= true ) { super (skin, replace); UIBuilder.buildAll( this ); } public   override   function  destory(): void { UIBuilder.destory( this ); super .destory(); } } public   class  Render  extends  GButton { public   var  nameText:GText; public   var  numText:GText; public   function  Render(skin:*= null ,  replace:Boolean= true ) { super (skin, replace); nameText =  new   GText( this .content[ "nameText" ]); numText =  new   GText( this .content[ "numText" ]); } public   override   function  destory(): void { nameText.destory(); numText.destory(); super .destory(); } }
关于队列 先看看需求
需求分析 先移动列表,然后修改数据,最后将列表移回原来的位置。 (因为数据不会立即生效,因此需要缓存在变量中) 更改数据后列表长度可能变化,所以需要将滚动重置。 重复执行这段代码会有各种问题,因此移动过程中按钮应当是禁用的。
是否打算这样去做? private   var  temp:Array; public   function  setData(v:Array): void { temp = v; tabBar.mouseEnabled = tabBar.mouseChildren =  false ; TweenUtil.to( this .render,500,{y:300,ease:Circ.easeIn,onComplete:tween1CompleteHandler}); } private   function  tween1CompleteHandler(): void { this .render.data = temp; temp =  null ; this .scrollBar.resetContent( true , false );// 重置滚动条 TweenUtil.to( this .render,500,{y:0,ease:Circ.easeOut,onComplete:tween2CompleteHandler}); } private   function  tween2CompleteHandler(): void { tabBar.mouseEnabled = tabBar.mouseChildren =  true ; }
另一种写法 public   function  setData( v :Array): void { var  list:Array = [ new  SetPropertyOper( this .tabBar,{mouseEnabled: false ,mouseChildren: false }), // 禁用鼠标 new  TweenOper( this .render,500,{y:300,ease:Circ.easeIn}), // 隐藏列表 new  SetPropertyOper( this .render,{data: v }), // 设置数据 new  FunctionOper( this .scrollBar.resetContent,[true,false]), // 让滚动区域回到顶端 new  TweenOper( this .render,500,{y:0,ease:Circ.easeOut}), // 显示列表 new  SetPropertyOper( this .tabBar,{mouseEnabled: true ,mouseChildren: true }) // 恢复鼠标 ]; new  Queue(list).execute(); // 队列执行 }
Oper 类 上面的代码是先创建了一个数组,数组里面都是一些继承于 Oper 的类,每个对象表示着一个具体操作。这个对象创建出来并不会立即执行,而要使用对象的 execute 方法来启动。 创建数组后,则创建了另一个特殊的 Oper : Queue ,它会代理并队列调用参数数组里的 Oper 对象的 execute 方法。 这种做法比加监听意义更加明确。
Queue 这是一个特殊的 Oper ,参数是一个数组包含着其他的 Oper 对象。执行它将会顺序执行所有子对象。 就像这样:  new  Queue(list).execute();
SetPropertyOper SetPropertyOper( this .tabBar,{mouseEnabled: false ,mouseChildren: false }), 这个类用于设置某个对象的属性,第一个参数是对象实例,第二个参数是一个 JSON 对象,例如这段代码就是设置 mouseEnabled,mouseChildren 的值为 false
TweenOper TweenOper( this .render,500,{y:300,ease:Circ.easeIn}) 和 Tween 参数相似,只不过实例化这个对象并不会马上执行 Tween 操作,而需要手动执行 execute 方法。用于队列这点是必须的。
FunctionOper FunctionOper( this .scrollBar.resetContent,[true,false]) 这个类非常简单,就是执行一个函数,第二个参数是参数数组。同样,你可以通过控制 execute 执行的时机来延迟执行这个函数。 例如,你想加载一个文件然后完毕时执行一个方法,也可以这样写 new Queue([new LoadOper(“a.txt”),new FunctionOper(rHandler)]).execute(); 这样在加载完 a.txt 之后便会继续执行 rHandler 方法
…… 除此之外还有很多 但更重要的是,你可以自己创建一个 Oper 的派生类,便可以和其他类放置在同一个队列中执行
一个简单的例子(设置发光提示点击某个对象,点击后继续执行) public   class  ClickOper  extends  Oper { public   var  target:Sprite; public   function  ClickOper(target:Sprite) { this .target = target; super (); } public   override   function  execute(): void { this .target.addEventListener(MouseEvent.CLICK,result); this .target.filters = [ new  GlowFilter(0xFFFFFF,1,16,16)] super .execute(); } public   override   function  result(event:*= null ): void { this .target.removeEventListener(MouseEvent.CLICK,result); this .target.filters = []; super .result(event); } }
GListBase 列表类
刚才示例的代码,只是将 tabBar 的类型由 Gbutton 改成了 GListBase public   class  Panel  extends  GBuilderBase { public   var  titleText:GText; public   var  mc:GMovieClip; //public var tabBar:GButton; public   var  tabBar: GListBase ; public   var  scrollBar:GHScrollBar; public   var  render: GListBase ; public   function  Panel3() { super ( &quot;asset.Panel&quot; ); mc.setLabel( null ,1); // 让动画只播放一次 render.type = UIConst.HORIZONTAL; render.itemRender = Render; scrollBar.setTarget(render,render.columnWidth * 2); scrollBar.detra = render.columnWidth; tabBar.type = UIConst.HORIZONTAL; tabBar.itemRender = GButton; tabBar.data = [ &quot;A-Z&quot; , &quot;0-10000&quot; ]; tabBar.addEventListener(Event.CHANGE,tabChangeHandler); tabBar.selectedIndex = 0; } private   function  tabChangeHandler(event:Event): void { setData(getData(tabBar.selectedIndex)) } private   function  getData(type:int):Array { var  i:int; var  list:Array = []; if  (type == 0) { for  (i = 0;i < 26;i++) { list[i] = String.fromCharCode(( &quot;A&quot; ).charCodeAt(0) + i); } } else { for  (i = 0;i < 100000;i++) { list[i] = i.toString(); }
GListBase 只负责复制子对象实现列表效果,它没有自己的大小概念,也没有滚动条。 它可以像列表那样加上滚动条使用,也可以像上面那样直接作为 TabBar 存在。 一共提供横向,纵向,横向平铺 3 种布局方式 (不要忘了,能够复制的 MC 必须绑定类,否则无法复制,将永远直显示一个子对象)
列表项的数量可以达到 1W GListBase 已经实现了对象池,只有显示出的子对象才会被实例化。因此显示 1W (或者更多)和显示 2 个消耗的资源是相同的。 上面的例子中的第 2 个 Tab 页就使用了一个 1W 项数据的列表
GMovieClip 动画扩展类
其实之前的例子已经出现了一次 public var mc:GMovieClip; public   function  Panel() { super ( &quot; asset.Panel &quot; ); // 连接资源 tabBar.data =  &quot;A&quot; ; nameText.text =  &quot;@name&quot; ; numText.text =  &quot;A&quot; ; mc.setLabel( null ,1); // 让动画只播放一次 } 就像注释说的那样,这段代码的作用是设置 mc 的播放范围为 null (也就是全部帧),并指定播放 1 次。这是一个通用写法,也可以换成 mc.setLoop(1) 是一样的效果。当然,如果把 1 改成 2 ,那就是播放 2 次后停止。
GMovieClip 关键属性 / 方法 frameRate  可以设置动画的播放帧频,当值为负时即为倒放,默认为舞台帧频 frameRate 的播放控制是基于时间的,因此并不会因为 CPU 忙而产生拖慢,而只会跳帧,相对于拖慢更难被用户察觉。 它是监听了 ENTER_FRAME 事件并以 getTimer 作为依据来决定当前帧的。并不会出现直接用 Timer 更新产生的闪烁,因此也不需要强制更新屏幕。
GMovieClip 关键属性 / 方法 setLabel( 帧标签,播放次数 ) 帧标签就是 FLASH 时间线上对帧的命名,播放次数为 -1 时为无限循环(默认值) queueLabel( 帧标签,播放次数 ) 这个方法需要和 setLabel 配合使用,它会在上一个动画播放完成后再执行。 clearQueue() 清除当前的动画队列
如果你的动画帧被命名分割为三个区域 : start ,  loop , end ,然后你希望先播放 start ,然后重复播放 loop 三次,最后播放完 end 然后停止,代码如下 setLabel(“start”,1); queueLabel(“loop”,3); queueLabel(“end”,1); 整个播放过程当然也会对外发布 MovieEvent 事件,如果希望在动画完毕时处理一些事情,监听动画的 MOVIE_EMPTY 事件
queueDestory() 新版本增加的方法,执行它后会在动画播放完毕后自动移除自己。于是不需要再去监听 MOVIE_EMPTY 事件了。毕竟这个需求就和动画仅播放一次一样常见…… 如果想反悔,可以再一次执行 clearQueue 方法。
并不只是矢量 GBitmapMovieClip 和它拥有几乎完全相同的属性和方法,但它所支持的是位图序列。 与 MovieClip 不同,它的构造函数参数是一个由 BitmapData 组成的数组。而重要的帧标签部分,则是第二个可选参数:一个 FrameLabel 组成的数组。
第二个参数并不是必须的。但如果想使用 queueLabel 这类方法的话,没有帧标签该如何操作?虽然,你也可以直接手动设置 currentFrame 你可以自己手动创建这个 FrameLabel 数组,也可以直接去取一个专门的空 MovieClip 的 currentLabels 属性(这是一条捷径)
一个 GBitmapMovieClip 的实例 只贴出相关部分( BitmapSeparateUtil , FrameLabelUtil 也是库中的类 ) var  source:Array = BitmapSeparateUtil.separateBitmapData( new  stand().bitmapData,56,91).concat(BitmapSeparateUtil.separateBitmapData( new  walk().bitmapData,67,91)); // 从 PNG 图片中切割成动画数组 var  labels:Array = FrameLabelUtil.createFromObject({ &quot;down&quot; :1, &quot;left&quot; :9, &quot;right&quot; :17, &quot;up&quot; :25, &quot;leftdown&quot; :33, &quot;rightdown&quot; :41, &quot;leftup&quot; :49, &quot;rightup&quot; :57, &quot;walkdown&quot; :65, &quot;walkleft&quot; :73, &quot;walkright&quot; :81, &quot;walkup&quot; :89, &quot;walkleftdown&quot; :97, &quot;walkrightdown&quot; :105, &quot;walkleftup&quot; :113, &quot;walkrightup&quot; :121 }); // 创建 FrameLabel 数组 man =  new  GBitmapMovieClip(source,labels);  // 创建动画对象 man.frameRate = 10;
动画缓存? 矢量动画太复杂,播放不顺畅?这时候只能缓存。但具体应当如何去做呢? 当矢量和位图动画拥有同样的方法的时候,缓存动画就很简单了。下面的代码最后都能生成一个 GBitmapMovieClip 对象 bmc ,它是 mc 这个 MovieClip 对象的缓存,并可以直接 addChild 显示。 方法 1 : bmc = new GBitmapMovieClip(); bmc.createFromMovieClip(mc); 方法 2 : bmc = new GMovieClip(mc).toGBitmapMovieClip();
SelectGroup& ViewStack 关于页面切换
asset.fla 同理, tabBar 和 viewStack 元件类分别包含着 tab1,tab2,tab3 以及 render1,render2,render3 整个元件链接了类名 asset.SelectGroup
Panel.as v4  ( 效果 ) public   class  Panel  extends  GBuilderBase { public   var  tab1:ZoomButton; public   var  tab2:ZoomButton; public   var  tab3:ZoomButton; public   var  tabBar:GBase; public   var  render1:Panel; public   var  render2:Panel2; public   var  render3:Panel3; public   var  viewStack:GViewState; public   var  selectGroup:SelectGroup; public   function  Panel() { super ( &quot;asset.SelectGroup&quot; ); // 按钮条 selectGroup =  new  SelectGroup([ tab1,tab2,tab3 ], true ); selectGroup.addEventListener(Event.CHANGE,  changeHandler ); selectGroup.selectedIndex = 0; // 设置切换过渡 viewStack.showFromRight =  new  TweenOper( null , 500, { x: -760, startAt:{x:0}, ease:Circ.easeInOut},  true ,1); viewStack.showFromLeft =  new  TweenOper( null , 500, { x:760, startAt:{x:0}, ease:Circ.easeInOut},  true ,1); viewStack.hideToRight =  new  TweenOper( null , 500, { x: -760 , ease:Circ.easeInOut},  false ,1); viewStack.hideToLeft =  new  TweenOper( null , 500, { x:760 , ease:Circ.easeInOut},  false ,1); } private   function   changeHandler (event:Event): void { viewStack.selectedIndex = selectGroup.selectedIndex; } } 其中 ZoomButton 类见下页
ZoomButton.as public   class  ZoomButton  extends  GButton { public   function  ZoomButton(skin:*=  null , replace:Boolean =  true ,  separateTextField:Boolean =  false , textPadding:Padding =  null ) { super (skin, replace, separateTextField, textPadding); this .delayCall =  false ; // 取消延迟更新避免抖动 this .upState.oper =  new  TweenOper( this ,100,{scaleX:1.0,scaleY:1.0},  false , 1); this .overState.oper =  new  TweenOper( this ,100,{scaleX:1.4,scaleY:1.4},  false , 1); this .downState.oper =  new  TweenOper( this ,100,{scaleX:1.0,scaleY:1.0},  false , 1); this .selectedUpState.oper =  this .selectedOverState.oper =  this .selectedDownState.oper =  new  TweenOper( this ,100,{scaleX:1.4,scaleY:1.4},  false , 1); this .disabledState.oper =  this .selectedDisabledState.oper =  new  TweenOper( this ,100,{scaleX:1.0,scaleY:1.0},  false , 1); } } 这个类直接继承于 GButton 并设置了一些效果的初始值,以实现缩放
SelectGroup // 按钮条 selectGroup =  new  SelectGroup([ tab1,tab2,tab3 ], true ); selectGroup.addEventListener(Event.CHANGE,  changeHandler ); selectGroup.selectedIndex = 0; 这个类会将多个按钮传入,并提供 selectedIndex,selectedChild 属性以及 Change 事件来方便实现类似 ToggleButtonBar 的效果 如果将第三个参数设置为” visible” ,还可以同样的指定多个对象仅有一个显示的效果
GViewState 此对象会将自己的 Children 当作多个 State 来处理,同时只显示其中的一个 ViewState 主要的特性是提供了 showFromRight,showFromLeft,hideToRight,hideToLeft 这 4 个 Effect 属性,可以在切换的时候显示转场。
Layout 布局
当你并不需要动态布局的时候 可以在生成界面之后手动设置 UI 的各个属性,如果有些数组无法简单的少量代码写出来的话,可以使用 LayoutUtil 静态类。 对齐  LayoutUtil.silder 从中部偏移  LayoutUtil.center 控制外框边距  LayoutUtil.metrics 百分比长宽  LayoutUtil.percent 横向排列  LayoutUtil.horizontal 纵向排列  LayoutUtil.vertical
当你需要动态布局的时候 使用 Layout 系列对象,将容器作为参数传入,并设置必要的属性(方向,边距,间距等),当容器的子对象都是 GBase 对象时即可自动布局 AbsoluteLayout  绝对布局,可设置子对象的 left,top,right,bottom 属性。 LinearLayout  线性布局,子对象会按顺序排列在一起,可指定为 HORIZONTAL, VERTICAL, TILE 三种模式
编写自己的 Layout 重写 Layout.as 的 layoutChildren 方法即可 protected   override   function  layoutChildren(x:Number, y:Number, w:Number, h:Number) { var  rx:Number = (w - paddingLeft - paddingRight) / 2;  var  ry:Number = (h - paddingTop - paddingBottom) / 2; var  sx:Number = x + paddingLeft + rx; var  sy:Number = y + paddingTop + ry; var  len:int = target.numChildren; var  br:Number =  this .rotation / 180 * Math.PI; for  ( var  i:int = 0;i < len;i++){ var  obj:DisplayObject = target.getChildAt(i); var  r:Number = i / len * Math.PI * 2 + br; var  p:Point =  new  Point(sx + rx * Math.cos(r),sy + ry * Math.sin(r)); obj.x = p.x; obj.y = p.y; } } 这段代码会让子对象以椭圆形式排列
当你希望容器本身也能根据子对象来决定自己大小的时候 Layout 对象需要实现 measureChildren 方法,最后通过执行 super .measureChildren(width,height) 来决定新的宽高 LinearLayout 布局器默认已经开启了 measureChildren 。如果会造成困扰,可以设置 enabledMeasureChildren=false 来取消这个效果。
GView GBox,GHBox,GVBox 已经默认包含了 LinearLayout 对象,因此只需要普通的 addChild 便能自动布局 任何时候都可以重新执行 setLayout 来指定布局器
例:给刚才的例子加上布局功能 ( 效果 ) public   var  tab1:ZoomButton; public   var  tab2:ZoomButton; public   var  tab3:ZoomButton; public   var  tabBar:GHBox;// 将 tabBar 的类型更改为 GHBox public   var  render1:Panel; public   var  render2:Panel2; public   var  render3:Panel3; public   var  viewStack:GViewState; public   var  selectGroup:SelectGroup; public   function  Panel(skin:*= null , replace:Boolean= true ) { super ( &quot;asset.SelectGroup&quot; ); tabBar.linearLayout.delayCall =  false ; // 取消延迟布局可减少运动时的抖动现象 tabBar.linearLayout.horizontalGap = 5; // 设置间距

More Related Content

PDF
由Hash Set谈重用
PPTX
Yui3入门
DOC
Google map api接口整理
PPT
Php & Mysql
PDF
GNOME3 延伸套件教學
PDF
Standford 2015 iOS讀書會 week2: 1. Applying MVC 2. More Swift and Foundation Fra...
PPTX
180518 ntut js and node
PDF
Python learn guide
由Hash Set谈重用
Yui3入门
Google map api接口整理
Php & Mysql
GNOME3 延伸套件教學
Standford 2015 iOS讀書會 week2: 1. Applying MVC 2. More Swift and Foundation Fra...
180518 ntut js and node
Python learn guide

What's hot (14)

PPTX
异步编程与浏览器执行模型
PDF
I os 05
PDF
Sql语句大全大全(经典珍藏版)
PPTX
Script with engine
PPTX
Python入門:5大概念初心者必備 2021/11/18
PDF
Jscex:案例、阻碍、体会、展望
PPTX
Python入門:5大概念初心者必備
PDF
Effective java 摘選條目分享 1 - 物件、複合、可變性、leak
PDF
Jscex:案例、经验、阻碍、展望
PPT
Javascript之昨是今非
PPTX
Groovy Introduction for Java Programmer
PDF
Node.js开发体验
PPT
JQuery Plugin
PDF
Open Street Map安裝指引 (Ubuntu 12.04)
异步编程与浏览器执行模型
I os 05
Sql语句大全大全(经典珍藏版)
Script with engine
Python入門:5大概念初心者必備 2021/11/18
Jscex:案例、阻碍、体会、展望
Python入門:5大概念初心者必備
Effective java 摘選條目分享 1 - 物件、複合、可變性、leak
Jscex:案例、经验、阻碍、展望
Javascript之昨是今非
Groovy Introduction for Java Programmer
Node.js开发体验
JQuery Plugin
Open Street Map安裝指引 (Ubuntu 12.04)
Ad

Viewers also liked (6)

PPS
PPT
松耦合代码之开发方法与工具演示 刘争辉
PPTX
Avm2虚拟机浅析与as3性能优化(陈士凯)
PPT
Flash media server 开发经验谈 沈先彬
PPT
Web base 吴志华
PPT
浅析Flash特效开发 陈勇
松耦合代码之开发方法与工具演示 刘争辉
Avm2虚拟机浅析与as3性能优化(陈士凯)
Flash media server 开发经验谈 沈先彬
Web base 吴志华
浅析Flash特效开发 陈勇
Ad

Similar to Ghost cat 以皮肤为主体的ui框架(唐翎) (20)

PDF
由一个简单的程序谈起--之四
PPT
DOC
用Jquery实现拖拽层
PPTX
Js的国(转载)
PDF
twMVC#27 | C# 7.0 新功能介紹
PDF
Android学习历程(3):用MVC进行重构
PDF
常見設計模式介紹
ODP
JavaScript Advanced Skill
PPTX
Javascript share
PPTX
前端MVC之backbone
PDF
Keep your code clean
PDF
M gui
PPTX
iOS swift 接力使力之玩 open data
PPT
组件交互模式的非主流研究
PPT
PPT
改善程序设计技术的50个有效做法
PDF
竞赛中C++语言拾遗
PPT
JavaScript 脚本控件(二)
PDF
Kissy component model
PPTX
从问题开始,谈前端架构
由一个简单的程序谈起--之四
用Jquery实现拖拽层
Js的国(转载)
twMVC#27 | C# 7.0 新功能介紹
Android学习历程(3):用MVC进行重构
常見設計模式介紹
JavaScript Advanced Skill
Javascript share
前端MVC之backbone
Keep your code clean
M gui
iOS swift 接力使力之玩 open data
组件交互模式的非主流研究
改善程序设计技术的50个有效做法
竞赛中C++语言拾遗
JavaScript 脚本控件(二)
Kissy component model
从问题开始,谈前端架构

More from FLASH开发者交流会 (20)

PPTX
Bambook sdk 与action script
PPTX
Bambook开放之路
PPT
Introduction to air for android 邱彦林
PPTX
Misato engine hugh_tsai-蔡浩宇
PPTX
Swf文件格式和abc代码混淆工具 黄珏坤
PPTX
Flash 独立游戏开发之路 徐黎明
PPTX
程序接口的另类理解与使用 孙毅
PPTX
Flash游戏大会 商文烨
PPT
Flash ria usability 刘轩飞
PPTX
9月18技术交流会大赛作品介绍 廖湘宁
PPTX
简化复杂的Flash应用程序 谈熠
PPTX
Flash mmorpg游戏引擎及工具开发概述-张明光
PPTX
Flash 游戏应用框架和模块化开发 邱广钦
PPTX
7月24日交流会麻球演讲 廖湘宁
PPT
Flash网络通讯处理 陈苏俊
PPT
轻量级Flash服务器开发框架(刘恒)
PDF
Flash 原型开发(刘磊)
PPTX
Actionscript中的元编程和开发流程解耦(谈熠)
PPT
Flex开发实践经验谈(谢敏)
PPT
Flash独立游戏 现状分析与发展思考(陈静)
Bambook sdk 与action script
Bambook开放之路
Introduction to air for android 邱彦林
Misato engine hugh_tsai-蔡浩宇
Swf文件格式和abc代码混淆工具 黄珏坤
Flash 独立游戏开发之路 徐黎明
程序接口的另类理解与使用 孙毅
Flash游戏大会 商文烨
Flash ria usability 刘轩飞
9月18技术交流会大赛作品介绍 廖湘宁
简化复杂的Flash应用程序 谈熠
Flash mmorpg游戏引擎及工具开发概述-张明光
Flash 游戏应用框架和模块化开发 邱广钦
7月24日交流会麻球演讲 廖湘宁
Flash网络通讯处理 陈苏俊
轻量级Flash服务器开发框架(刘恒)
Flash 原型开发(刘磊)
Actionscript中的元编程和开发流程解耦(谈熠)
Flex开发实践经验谈(谢敏)
Flash独立游戏 现状分析与发展思考(陈静)

Ghost cat 以皮肤为主体的ui框架(唐翎)

  • 2. 准备工作 创建工程 导入 Ghost Cat SWC 文件 创建资源 FLA 文件 asset.fla 创建多语言配置文件 ui.lang (可选)
  • 3. asset.fla 内容如图所示 其中 upArrow,downArrow 元件位于 scrollBar 元件中, nameText,numText 位于 render 元件中。所示文字表示的是元件在场景中的示例名。 整个图形绑定了类名 asset.Panel (此外, tabBar 和 render 由于在之后会被复制,也绑定了类名 asset.TabBar,asset.Render ,但这个类名只是用于复制,代码中并不会出现,其实无论取什么名字都没有关系)
  • 4. UI.lang 多语言并不是必须的,只是这个例子中包含了此特性。在之后的代码会会自动转换。 内容只有两行 name= 新的文字 title= 标题栏 在后面的代码中, @name 会被自动转换为“ 新的文字 ”, @title 会被自动转换为“ 标题栏 ”,将不再进行解释
  • 5. 建立文档类 public class test extends Sprite { public function test() { LanguageManager.instance.load( &quot; ui.lang &quot; ); // 加载多语言 AssetManager.instance.loadResource( &quot; asset.swf &quot; ); // 加载资源 Queue.defaultQueue.addEventListener(OperationEvent.OPERATION_COMPLETE,loadCompleteHandler);// 监听资源加载完成事件 } private function loadCompleteHandler(event:OperationEvent): void { stage.addChild(new ToolTipSprite());// 加入提示框 addChild( new Panel ());// 显示 Panel 窗体 } }
  • 6. Panel.as ( 效果 ) public class Panel extends GBuilderBase // 继承此类便有拥有全部特性 { public var titleText:GText; public var mc:GMovieClip; public var tabBar:GButton; public var upArrow:GButton; public var downArrow:GButton; public var nameText:GText; public var numText:GText; public function Panel() { super ( &quot; asset.Panel &quot; ); // 连接资源 tabBar.data = &quot;A&quot; ; nameText.text = &quot;@name&quot; ; numText.text = &quot;A&quot; ; mc.setLabel( null ,1); // 让动画只播放一次 } } 类名 asset.Panel 资源和类属性名称一一对应
  • 7. Panel.as v2 ( 效果 ) public class Panel extends GBuilderBase { public var titleText:GText; public var mc:GMovieClip; public var tabBar:GButton; //public var upArrow:GButton; //public var downArrow:GButton; public var scrollBar :GHScrollBar; //public var nameText:GText; //public var numText:GText; public var render :GListBase; public function Panel() { super ( “asset.Panel” );// 仍然使用原来的资源 mc.setLabel( null ,1); // 让动画只播放一次 tabBar.data = &quot;GhostCat&quot; ; render.type = UIConst.HORIZONTAL; // 设置 List 方向 render.itemRender = Render ; // 设置 Render render.data = [ &quot;G&quot; , &quot;H&quot; , &quot;O&quot; , &quot;S&quot; , &quot;T&quot; , &quot; &quot; , &quot;C&quot; , &quot;A&quot; , &quot;T&quot; ]; scrollBar.setTarget(render,render.columnWidth * 2); // 指定滚动条 scrollBar.detra = render.columnWidth; // 指定滚动距离 new ZoomEffect( this , null ,0.1,1000,{ease:Elastic.easeIn}, true ).execute();// 展开效果 } } 这里直接定义父层元件,滚动条的两个按钮自动声明,而 render 则在 Render.as 中定义 设置列表的伸展方向,渲染器 ( 见下页,内容,设置滚动区域,滚动速度 最后加入一个从中间展开的效果
  • 8. Render.as public class Render extends GBuilderBase { public var nameText:GText; public var numText:GText; public function Render(skin:*= null , replace:Boolean= true ) { super (skin, replace);// 保持默认值,皮肤由外部传入 } // 复写 data 的 set 方法来获得数据 public override function set data(v:*) : void { super .data = v; nameText.text = numText.text = v; this .toolTip = &quot; 当前值: &quot; + v; TextFieldUtil.autoFontSize(numText.textField); // 调整字号使得可以全部显示 } // 复写 selected 属性来设置选中效果 public override function set selected(v:Boolean) : void { super .selected = v; this .transform.colorTransform = v ? new ColorTransform(1,1,1,1,50,50,50) : new ColorTransform(); } }
  • 9. 已经有基类,不能直接使用 GBuildBase? public class Render extends GButton { public var nameText:GText; public var numText:GText; public function Render(skin:*= null , replace:Boolean= true ) { super (skin, replace); UIBuilder.buildAll( this ); } public override function destory(): void { UIBuilder.destory( this ); super .destory(); } } public class Render extends GButton { public var nameText:GText; public var numText:GText; public function Render(skin:*= null , replace:Boolean= true ) { super (skin, replace); nameText = new GText( this .content[ &quot;nameText&quot; ]); numText = new GText( this .content[ &quot;numText&quot; ]); } public override function destory(): void { nameText.destory(); numText.destory(); super .destory(); } }
  • 11. 需求分析 先移动列表,然后修改数据,最后将列表移回原来的位置。 (因为数据不会立即生效,因此需要缓存在变量中) 更改数据后列表长度可能变化,所以需要将滚动重置。 重复执行这段代码会有各种问题,因此移动过程中按钮应当是禁用的。
  • 12. 是否打算这样去做? private var temp:Array; public function setData(v:Array): void { temp = v; tabBar.mouseEnabled = tabBar.mouseChildren = false ; TweenUtil.to( this .render,500,{y:300,ease:Circ.easeIn,onComplete:tween1CompleteHandler}); } private function tween1CompleteHandler(): void { this .render.data = temp; temp = null ; this .scrollBar.resetContent( true , false );// 重置滚动条 TweenUtil.to( this .render,500,{y:0,ease:Circ.easeOut,onComplete:tween2CompleteHandler}); } private function tween2CompleteHandler(): void { tabBar.mouseEnabled = tabBar.mouseChildren = true ; }
  • 13. 另一种写法 public function setData( v :Array): void { var list:Array = [ new SetPropertyOper( this .tabBar,{mouseEnabled: false ,mouseChildren: false }), // 禁用鼠标 new TweenOper( this .render,500,{y:300,ease:Circ.easeIn}), // 隐藏列表 new SetPropertyOper( this .render,{data: v }), // 设置数据 new FunctionOper( this .scrollBar.resetContent,[true,false]), // 让滚动区域回到顶端 new TweenOper( this .render,500,{y:0,ease:Circ.easeOut}), // 显示列表 new SetPropertyOper( this .tabBar,{mouseEnabled: true ,mouseChildren: true }) // 恢复鼠标 ]; new Queue(list).execute(); // 队列执行 }
  • 14. Oper 类 上面的代码是先创建了一个数组,数组里面都是一些继承于 Oper 的类,每个对象表示着一个具体操作。这个对象创建出来并不会立即执行,而要使用对象的 execute 方法来启动。 创建数组后,则创建了另一个特殊的 Oper : Queue ,它会代理并队列调用参数数组里的 Oper 对象的 execute 方法。 这种做法比加监听意义更加明确。
  • 15. Queue 这是一个特殊的 Oper ,参数是一个数组包含着其他的 Oper 对象。执行它将会顺序执行所有子对象。 就像这样: new Queue(list).execute();
  • 16. SetPropertyOper SetPropertyOper( this .tabBar,{mouseEnabled: false ,mouseChildren: false }), 这个类用于设置某个对象的属性,第一个参数是对象实例,第二个参数是一个 JSON 对象,例如这段代码就是设置 mouseEnabled,mouseChildren 的值为 false
  • 17. TweenOper TweenOper( this .render,500,{y:300,ease:Circ.easeIn}) 和 Tween 参数相似,只不过实例化这个对象并不会马上执行 Tween 操作,而需要手动执行 execute 方法。用于队列这点是必须的。
  • 18. FunctionOper FunctionOper( this .scrollBar.resetContent,[true,false]) 这个类非常简单,就是执行一个函数,第二个参数是参数数组。同样,你可以通过控制 execute 执行的时机来延迟执行这个函数。 例如,你想加载一个文件然后完毕时执行一个方法,也可以这样写 new Queue([new LoadOper(“a.txt”),new FunctionOper(rHandler)]).execute(); 这样在加载完 a.txt 之后便会继续执行 rHandler 方法
  • 19. …… 除此之外还有很多 但更重要的是,你可以自己创建一个 Oper 的派生类,便可以和其他类放置在同一个队列中执行
  • 20. 一个简单的例子(设置发光提示点击某个对象,点击后继续执行) public class ClickOper extends Oper { public var target:Sprite; public function ClickOper(target:Sprite) { this .target = target; super (); } public override function execute(): void { this .target.addEventListener(MouseEvent.CLICK,result); this .target.filters = [ new GlowFilter(0xFFFFFF,1,16,16)] super .execute(); } public override function result(event:*= null ): void { this .target.removeEventListener(MouseEvent.CLICK,result); this .target.filters = []; super .result(event); } }
  • 22. 刚才示例的代码,只是将 tabBar 的类型由 Gbutton 改成了 GListBase public class Panel extends GBuilderBase { public var titleText:GText; public var mc:GMovieClip; //public var tabBar:GButton; public var tabBar: GListBase ; public var scrollBar:GHScrollBar; public var render: GListBase ; public function Panel3() { super ( &quot;asset.Panel&quot; ); mc.setLabel( null ,1); // 让动画只播放一次 render.type = UIConst.HORIZONTAL; render.itemRender = Render; scrollBar.setTarget(render,render.columnWidth * 2); scrollBar.detra = render.columnWidth; tabBar.type = UIConst.HORIZONTAL; tabBar.itemRender = GButton; tabBar.data = [ &quot;A-Z&quot; , &quot;0-10000&quot; ]; tabBar.addEventListener(Event.CHANGE,tabChangeHandler); tabBar.selectedIndex = 0; } private function tabChangeHandler(event:Event): void { setData(getData(tabBar.selectedIndex)) } private function getData(type:int):Array { var i:int; var list:Array = []; if (type == 0) { for (i = 0;i < 26;i++) { list[i] = String.fromCharCode(( &quot;A&quot; ).charCodeAt(0) + i); } } else { for (i = 0;i < 100000;i++) { list[i] = i.toString(); }
  • 23. GListBase 只负责复制子对象实现列表效果,它没有自己的大小概念,也没有滚动条。 它可以像列表那样加上滚动条使用,也可以像上面那样直接作为 TabBar 存在。 一共提供横向,纵向,横向平铺 3 种布局方式 (不要忘了,能够复制的 MC 必须绑定类,否则无法复制,将永远直显示一个子对象)
  • 24. 列表项的数量可以达到 1W GListBase 已经实现了对象池,只有显示出的子对象才会被实例化。因此显示 1W (或者更多)和显示 2 个消耗的资源是相同的。 上面的例子中的第 2 个 Tab 页就使用了一个 1W 项数据的列表
  • 26. 其实之前的例子已经出现了一次 public var mc:GMovieClip; public function Panel() { super ( &quot; asset.Panel &quot; ); // 连接资源 tabBar.data = &quot;A&quot; ; nameText.text = &quot;@name&quot; ; numText.text = &quot;A&quot; ; mc.setLabel( null ,1); // 让动画只播放一次 } 就像注释说的那样,这段代码的作用是设置 mc 的播放范围为 null (也就是全部帧),并指定播放 1 次。这是一个通用写法,也可以换成 mc.setLoop(1) 是一样的效果。当然,如果把 1 改成 2 ,那就是播放 2 次后停止。
  • 27. GMovieClip 关键属性 / 方法 frameRate 可以设置动画的播放帧频,当值为负时即为倒放,默认为舞台帧频 frameRate 的播放控制是基于时间的,因此并不会因为 CPU 忙而产生拖慢,而只会跳帧,相对于拖慢更难被用户察觉。 它是监听了 ENTER_FRAME 事件并以 getTimer 作为依据来决定当前帧的。并不会出现直接用 Timer 更新产生的闪烁,因此也不需要强制更新屏幕。
  • 28. GMovieClip 关键属性 / 方法 setLabel( 帧标签,播放次数 ) 帧标签就是 FLASH 时间线上对帧的命名,播放次数为 -1 时为无限循环(默认值) queueLabel( 帧标签,播放次数 ) 这个方法需要和 setLabel 配合使用,它会在上一个动画播放完成后再执行。 clearQueue() 清除当前的动画队列
  • 29. 如果你的动画帧被命名分割为三个区域 : start , loop , end ,然后你希望先播放 start ,然后重复播放 loop 三次,最后播放完 end 然后停止,代码如下 setLabel(“start”,1); queueLabel(“loop”,3); queueLabel(“end”,1); 整个播放过程当然也会对外发布 MovieEvent 事件,如果希望在动画完毕时处理一些事情,监听动画的 MOVIE_EMPTY 事件
  • 30. queueDestory() 新版本增加的方法,执行它后会在动画播放完毕后自动移除自己。于是不需要再去监听 MOVIE_EMPTY 事件了。毕竟这个需求就和动画仅播放一次一样常见…… 如果想反悔,可以再一次执行 clearQueue 方法。
  • 31. 并不只是矢量 GBitmapMovieClip 和它拥有几乎完全相同的属性和方法,但它所支持的是位图序列。 与 MovieClip 不同,它的构造函数参数是一个由 BitmapData 组成的数组。而重要的帧标签部分,则是第二个可选参数:一个 FrameLabel 组成的数组。
  • 32. 第二个参数并不是必须的。但如果想使用 queueLabel 这类方法的话,没有帧标签该如何操作?虽然,你也可以直接手动设置 currentFrame 你可以自己手动创建这个 FrameLabel 数组,也可以直接去取一个专门的空 MovieClip 的 currentLabels 属性(这是一条捷径)
  • 33. 一个 GBitmapMovieClip 的实例 只贴出相关部分( BitmapSeparateUtil , FrameLabelUtil 也是库中的类 ) var source:Array = BitmapSeparateUtil.separateBitmapData( new stand().bitmapData,56,91).concat(BitmapSeparateUtil.separateBitmapData( new walk().bitmapData,67,91)); // 从 PNG 图片中切割成动画数组 var labels:Array = FrameLabelUtil.createFromObject({ &quot;down&quot; :1, &quot;left&quot; :9, &quot;right&quot; :17, &quot;up&quot; :25, &quot;leftdown&quot; :33, &quot;rightdown&quot; :41, &quot;leftup&quot; :49, &quot;rightup&quot; :57, &quot;walkdown&quot; :65, &quot;walkleft&quot; :73, &quot;walkright&quot; :81, &quot;walkup&quot; :89, &quot;walkleftdown&quot; :97, &quot;walkrightdown&quot; :105, &quot;walkleftup&quot; :113, &quot;walkrightup&quot; :121 }); // 创建 FrameLabel 数组 man = new GBitmapMovieClip(source,labels); // 创建动画对象 man.frameRate = 10;
  • 34. 动画缓存? 矢量动画太复杂,播放不顺畅?这时候只能缓存。但具体应当如何去做呢? 当矢量和位图动画拥有同样的方法的时候,缓存动画就很简单了。下面的代码最后都能生成一个 GBitmapMovieClip 对象 bmc ,它是 mc 这个 MovieClip 对象的缓存,并可以直接 addChild 显示。 方法 1 : bmc = new GBitmapMovieClip(); bmc.createFromMovieClip(mc); 方法 2 : bmc = new GMovieClip(mc).toGBitmapMovieClip();
  • 36. asset.fla 同理, tabBar 和 viewStack 元件类分别包含着 tab1,tab2,tab3 以及 render1,render2,render3 整个元件链接了类名 asset.SelectGroup
  • 37. Panel.as v4 ( 效果 ) public class Panel extends GBuilderBase { public var tab1:ZoomButton; public var tab2:ZoomButton; public var tab3:ZoomButton; public var tabBar:GBase; public var render1:Panel; public var render2:Panel2; public var render3:Panel3; public var viewStack:GViewState; public var selectGroup:SelectGroup; public function Panel() { super ( &quot;asset.SelectGroup&quot; ); // 按钮条 selectGroup = new SelectGroup([ tab1,tab2,tab3 ], true ); selectGroup.addEventListener(Event.CHANGE, changeHandler ); selectGroup.selectedIndex = 0; // 设置切换过渡 viewStack.showFromRight = new TweenOper( null , 500, { x: -760, startAt:{x:0}, ease:Circ.easeInOut}, true ,1); viewStack.showFromLeft = new TweenOper( null , 500, { x:760, startAt:{x:0}, ease:Circ.easeInOut}, true ,1); viewStack.hideToRight = new TweenOper( null , 500, { x: -760 , ease:Circ.easeInOut}, false ,1); viewStack.hideToLeft = new TweenOper( null , 500, { x:760 , ease:Circ.easeInOut}, false ,1); } private function changeHandler (event:Event): void { viewStack.selectedIndex = selectGroup.selectedIndex; } } 其中 ZoomButton 类见下页
  • 38. ZoomButton.as public class ZoomButton extends GButton { public function ZoomButton(skin:*= null , replace:Boolean = true , separateTextField:Boolean = false , textPadding:Padding = null ) { super (skin, replace, separateTextField, textPadding); this .delayCall = false ; // 取消延迟更新避免抖动 this .upState.oper = new TweenOper( this ,100,{scaleX:1.0,scaleY:1.0}, false , 1); this .overState.oper = new TweenOper( this ,100,{scaleX:1.4,scaleY:1.4}, false , 1); this .downState.oper = new TweenOper( this ,100,{scaleX:1.0,scaleY:1.0}, false , 1); this .selectedUpState.oper = this .selectedOverState.oper = this .selectedDownState.oper = new TweenOper( this ,100,{scaleX:1.4,scaleY:1.4}, false , 1); this .disabledState.oper = this .selectedDisabledState.oper = new TweenOper( this ,100,{scaleX:1.0,scaleY:1.0}, false , 1); } } 这个类直接继承于 GButton 并设置了一些效果的初始值,以实现缩放
  • 39. SelectGroup // 按钮条 selectGroup = new SelectGroup([ tab1,tab2,tab3 ], true ); selectGroup.addEventListener(Event.CHANGE, changeHandler ); selectGroup.selectedIndex = 0; 这个类会将多个按钮传入,并提供 selectedIndex,selectedChild 属性以及 Change 事件来方便实现类似 ToggleButtonBar 的效果 如果将第三个参数设置为” visible” ,还可以同样的指定多个对象仅有一个显示的效果
  • 40. GViewState 此对象会将自己的 Children 当作多个 State 来处理,同时只显示其中的一个 ViewState 主要的特性是提供了 showFromRight,showFromLeft,hideToRight,hideToLeft 这 4 个 Effect 属性,可以在切换的时候显示转场。
  • 42. 当你并不需要动态布局的时候 可以在生成界面之后手动设置 UI 的各个属性,如果有些数组无法简单的少量代码写出来的话,可以使用 LayoutUtil 静态类。 对齐 LayoutUtil.silder 从中部偏移 LayoutUtil.center 控制外框边距 LayoutUtil.metrics 百分比长宽 LayoutUtil.percent 横向排列 LayoutUtil.horizontal 纵向排列 LayoutUtil.vertical
  • 43. 当你需要动态布局的时候 使用 Layout 系列对象,将容器作为参数传入,并设置必要的属性(方向,边距,间距等),当容器的子对象都是 GBase 对象时即可自动布局 AbsoluteLayout 绝对布局,可设置子对象的 left,top,right,bottom 属性。 LinearLayout 线性布局,子对象会按顺序排列在一起,可指定为 HORIZONTAL, VERTICAL, TILE 三种模式
  • 44. 编写自己的 Layout 重写 Layout.as 的 layoutChildren 方法即可 protected override function layoutChildren(x:Number, y:Number, w:Number, h:Number) { var rx:Number = (w - paddingLeft - paddingRight) / 2; var ry:Number = (h - paddingTop - paddingBottom) / 2; var sx:Number = x + paddingLeft + rx; var sy:Number = y + paddingTop + ry; var len:int = target.numChildren; var br:Number = this .rotation / 180 * Math.PI; for ( var i:int = 0;i < len;i++){ var obj:DisplayObject = target.getChildAt(i); var r:Number = i / len * Math.PI * 2 + br; var p:Point = new Point(sx + rx * Math.cos(r),sy + ry * Math.sin(r)); obj.x = p.x; obj.y = p.y; } } 这段代码会让子对象以椭圆形式排列
  • 45. 当你希望容器本身也能根据子对象来决定自己大小的时候 Layout 对象需要实现 measureChildren 方法,最后通过执行 super .measureChildren(width,height) 来决定新的宽高 LinearLayout 布局器默认已经开启了 measureChildren 。如果会造成困扰,可以设置 enabledMeasureChildren=false 来取消这个效果。
  • 46. GView GBox,GHBox,GVBox 已经默认包含了 LinearLayout 对象,因此只需要普通的 addChild 便能自动布局 任何时候都可以重新执行 setLayout 来指定布局器
  • 47. 例:给刚才的例子加上布局功能 ( 效果 ) public var tab1:ZoomButton; public var tab2:ZoomButton; public var tab3:ZoomButton; public var tabBar:GHBox;// 将 tabBar 的类型更改为 GHBox public var render1:Panel; public var render2:Panel2; public var render3:Panel3; public var viewStack:GViewState; public var selectGroup:SelectGroup; public function Panel(skin:*= null , replace:Boolean= true ) { super ( &quot;asset.SelectGroup&quot; ); tabBar.linearLayout.delayCall = false ; // 取消延迟布局可减少运动时的抖动现象 tabBar.linearLayout.horizontalGap = 5; // 设置间距