iPhone开发讲座第一讲 iOS简介

15 十一 2011 In: iOS

转自 iApp4Me.com创始人 @tinyfool 老师。

分享到新浪微博 分享到人人网 分享到豆瓣 分享到鲜果 分享到百度空间 分享到开心网 QQ书签 分享到YAHOO! 分享到Google Google Buzz 分享到Facebook 分享到Plurk Digg delicious Technorati Twitter

自訂 Flex 滑鼠游標實體

5 十一 2011 In: ActionScript3, Flex

遇到一個問題是,想要自訂 Flex App 的 Cursor 可是又要能存取 Cursor 實體
以便做其他的動態控制
可是 Flex CursorManager 基本上是不允許這樣做的
只能以 Class 方式設定 Cursor,也無法存取到目前 Cursor 實體
網路上有人提過解決方式 Jesse Warden – Making a Cooler Cursor in Flex
可是他是藉由 Hack CursorManager 方式做到
實際用 Flex 4.5 測試,發現只要將編譯模式從 Merged into code 改為 RSL
這個方法就失效了,只好自行另外想辦法

觀察 StyleManager 實作,發現 Cursor 實體是放在 systemManager.cursorChildren > cursorHolder 內
於是想到可以自行指定空的 Sprite 作為 Cursor,然後自行取出 Cursor 實體
另外再加以控制

CustomCursorPanel1.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  width="400" height="300" title="Custom Cursor Panel 1"
  rollOver="onRollOverHandler(event);"
  rollOut="onRollOutHandler(event);">
 <fx:Declarations>
  <flash:TextField id="cursorTxt" xmlns:flash="flash.text.*" border="true" autoSize="left" />
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import mx.core.IChildList;
 
   protected var cursorID:int;
 
   public function onRollOverHandler(e:MouseEvent):void{
    cursorID = cursorManager.setCursor(Sprite);
 
    var cursorChildren:IChildList = systemManager.cursorChildren;
    if (!cursorChildren) return;
    var cursorHolder:Sprite = cursorChildren.getChildByName("cursorHolder") as Sprite;
    if (!cursorHolder || !cursorHolder.numChildren) return;
    var cursor:Sprite = cursorHolder.getChildAt(0) as Sprite;
    if (!cursor) return;
    cursor.addChildAt(cursorTxt, 0);
 
    addEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onRollOutHandler(e:MouseEvent):void{
    cursorManager.removeCursor(cursorID);
    removeEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onMouseEventHandler(e:MouseEvent):void{
    cursorTxt.text = e.type + " ("+ e.localX + " : " + e.localY + ")";
   }
  ]]>
 </fx:Script>
</s:Panel>

CustomCursorPanel1 實際範例

This movie requires Flash Player 9

不過缺點是萬一 CursorManager 實作方式大改可能就會失效了
所以又想了另一個方式
實做一個 CursorProxy 類別

package com.ticore.utils  {
 import flash.display.DisplayObject;
 import flash.display.Sprite;
 
 /**
  * 提供一個 proxy 類別,給 Flex CursorManager 設定 cursor
  * CursorProxy 另外宣告一靜態的 getter/setter 供存取 cursor 實體
  * 每次 CursorProxy 實體被創建時,都會將靜態 cursor 實體加入自己 display list 下
  * 
  * @author Ticore Shih
  */
 public class CursorProxy extends Sprite {
 
  static protected var _cursor_:DisplayObject;
 
  static public function get cursor():DisplayObject{
   return _cursor_;
  }
 
  static public function set cursor(value:DisplayObject):void{
   _cursor_ = value;
   if (!_cursorProxy_) return;
   while (_cursorProxy_.numChildren) {
    _cursorProxy_.removeChildAt(0);
   }
   _cursorProxy_.addChild(_cursor_);
  }
 
 
  static protected var _cursorProxy_:CursorProxy;
 
  public function CursorProxy() {
   _cursorProxy_ = this;
   if (_cursor_) _cursorProxy_.addChild(_cursor_);
  }
 }
}

使用範例如下 CustomCursorPanel2.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  width="400" height="300" title="Custom Cursor Panel 1"
  rollOver="onRollOverHandler(event);"
  rollOut="onRollOutHandler(event);">
 <fx:Declarations>
  <flash:TextField id="cursorTxt" xmlns:flash="flash.text.*" border="true" autoSize="left" />
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import com.ticore.utils.CursorProxy;
   import mx.core.IChildList;
 
   protected var cursorID:int;
 
   public function onRollOverHandler(e:MouseEvent):void{
 
    cursorID = cursorManager.setCursor(CursorProxy);
    CursorProxy.cursor = cursorTxt;
    addEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    addEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onRollOutHandler(e:MouseEvent):void{
    cursorManager.removeCursor(cursorID);
    removeEventListener(MouseEvent.MOUSE_MOVE, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_DOWN, onMouseEventHandler);
    removeEventListener(MouseEvent.MOUSE_UP, onMouseEventHandler);
   }
 
   public function onMouseEventHandler(e:MouseEvent):void{
    cursorTxt.text = e.type + " ("+ e.localX + " : " + e.localY + ")";
   }
  ]]>
 </fx:Script>
</s:Panel>

CustomCursorPanel2 實際範例

This movie requires Flash Player 9

原始檔案下載

分享到新浪微博 分享到人人网 分享到豆瓣 分享到鲜果 分享到百度空间 分享到开心网 QQ书签 分享到YAHOO! 分享到Google Google Buzz 分享到Facebook 分享到Plurk Digg delicious Technorati Twitter

Flex App 直接引用外部 Module 的問題

4 十一 2011 In: ActionScript3, Flex

最近同事遇到一個 Flex 問題,只要 Module 內放了其它組件
執行就會出現各種奇怪 Error
後來發現是因為在 Main Application 直接引用編譯到 Module Class
然後又企圖用 ModuleLoader 再載入一次相同的 Module SWF
當然這樣做是錯誤的範例,Flash Builder 也會給予警告

Warning: Mod is a module or application that is directly referenced.
This will cause Mod and all of its dependencies to be linked in with MainApp.
Using an interface is the recommended practice to avoid this.

不要明確引用就正常了
不過還是覺得有點不合理,至少應該能正常執行吧

譬如以下的例子 MainApp.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
     xmlns:s="library://ns.adobe.com/flex/spark" 
     xmlns:mx="library://ns.adobe.com/flex/mx">
 <fx:Script>
  <![CDATA[
   Mod;
  ]]>
 </fx:Script>
 <s:layout>
  <s:VerticalLayout verticalAlign="middle" horizontalAlign="center" />
 </s:layout>
 <s:ModuleLoader id="modLdr" url="Mod.swf" width="50%" height="50%"/>
</s:Application>

直接引用到外部 Module,又企圖載入一次同一個外部 Module – Mod.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx"
  width="100%" height="100%">
 <s:Panel width="100%" height="100%" title="Module" />
</s:Module>

隨著 Module 內放置組件不同,可能會得到以下各種錯誤訊息

Main Thread (Suspended: ArgumentError: Error #2004: 有一個參數無效。)
flash.display::Graphics/drawRect [no source]
spark.components.supportClasses::TextBase/updateDisplayList
mx.core::UIComponent/validateDisplayList
mx.managers::LayoutManager/validateDisplayList
mx.managers::LayoutManager/doPhasedInstantiation
mx.managers::LayoutManager/doPhasedInstantiationCallback

Main Thread (Suspended: TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。)
mx.core::UIComponent/getStyle
mx.core::UIComponent/getConstraintValue
mx.core::UIComponent/get horizontalCenter
spark.layouts::BasicLayout/measure
spark.components.supportClasses::GroupBase/measure
mx.core::UIComponent/measureSizes
mx.core::UIComponent/validateSize
spark.components::Group/validateSize
mx.managers::LayoutManager/validateSize
mx.managers::LayoutManager/doPhasedInstantiation
mx.managers::LayoutManager/doPhasedInstantiationCallback

Flex ModuleLoader 預設載入外部 Module 時
是會從目前 ApplicationDomain 建立一個 child ApplicationDomain 作為載入之用
也就是說假如 Main App 已經包含一份 Module 定義
再載入同名類別,就會被前面的類別定義覆蓋
實際上,被 new 出來的實體其實是 Main App 內定義的

假如兩份定義完全一樣,應該也是要能正常執行吧
問題就是出在這裡了,用 ASV 分別去觀察兩個 SWF 內的 Module 類別
發現是不一樣的!

當 Flex Module 編譯為獨立 SWF 時
MXMLC Compiler 會塞入一些額外的 Metadata Tag, Code… 做初始化
可是 MainApp 內的 Module 定義少了這些動作,導致無法正常執行

解決的方式不難,ModuleLoader Ready 時
自己手動執行一下關鍵的初始動作就好了 – styleManager.initProtoChainRoots();

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
     xmlns:s="library://ns.adobe.com/flex/spark" 
     xmlns:mx="library://ns.adobe.com/flex/mx">
 <fx:Script>
  <![CDATA[
   Mod;
  ]]>
 </fx:Script>
 <s:layout>
  <s:VerticalLayout verticalAlign="middle" horizontalAlign="center" />
 </s:layout>
 <s:ModuleLoader id="modLdr" url="Mod.swf" width="50%" height="50%"
   ready="event.target.child.styleManager.initProtoChainRoots();" />
</s:Application>
分享到新浪微博 分享到人人网 分享到豆瓣 分享到鲜果 分享到百度空间 分享到开心网 QQ书签 分享到YAHOO! 分享到Google Google Buzz 分享到Facebook 分享到Plurk Digg delicious Technorati Twitter

Away3D4 stage3D Coverflow

2 十一 2011 In: ActionScript3, Flash

大家好,我是奶綠茶
今天來分享一下如何使用 Away3D4 製作經典的 Coverflow 效果
之前都是習慣用 PV3D 製作,但 PV3D 沒有推出 Stage3D 的版本,只好轉戰 Away3D
還好之前有玩過,寫起來長的差不多。
原理和之前分享過的幾篇 Coverflow 教學一樣
同時也練習了一下 Robotlegs , Demo如下。

away3d

SourceCodeDownload(DropBox)
在線Demo
Source
其中 ScrollBar 類別是使用 clockmaker 這篇的教學
http://clockmaker.jp/blog/2011/10/stage3d-cover-flow/

分享到新浪微博 分享到人人网 分享到豆瓣 分享到鲜果 分享到百度空间 分享到开心网 QQ书签 分享到YAHOO! 分享到Google Google Buzz 分享到Facebook 分享到Plurk Digg delicious Technorati Twitter

AS3 Cross Join Function

1 十一 2011 In: ActionScript3, Flash

昨天想要用各種不同條件測試 Flash AS3 的畫線
用過 graphics.lineStyle 應該知道參數很多種
但總不可能把各種條件組合通通打出來測試
就算用一般 Loop 方式,也要寫到四~五層 Loop
於是想要寫一個類似 SQL Cross Join 的 function
可以傳入不定數量的資料,將所有排列組合結果找出來

一開始寫時候,大約用了十來行
不斷改進之後,程式碼比想像中少很多
而且連一個區域變數都沒宣告
用了三層 Loop 完成

以下便是 AS3 Cross Join 公用函式:

package com.ticore.utils {
 /**
  * 排列組合公用函式,可以對傳入的二維參數陣列
  * 找出各種組合,並將結果陣列回傳
  * 
  * @param args 任意數量的二維參數陣列
  * @param res 欲與其它條件再組合的結果陣列
  * @return 二維結果陣列
  * @author Ticore Shih
  * 
  * @example 以下例子會找出 [A, B] 與 [0, 1, 2] 所有可能的組合
  * <listing version="3.0">
  * trace(crossJoin([["A", "B"], [0, 1, 2]]).join("\n"));
  * </listing>
  */
 public function crossJoin(args:Array, res:Array = null):Array{
  args.forEach(function(o0:*, i0:int, a0:Array):void{
   (res ||= [[]]).splice(0).forEach(function(o1:*, i1:int, a1:Array):void{
    o0.forEach(function(o2:*, i2:int, a2:Array):void{
     res.push(o1.concat(o2));
    });
   });
  });
  return res;
 }
}

實際使用例子

trace(crossJoin([['a', 'b']], crossJoin([["A", "B"], [0, 1, 2]])).join(“\n”));
/*/
A,0,a
A,0,b
A,1,a
A,1,b
A,2,a
A,2,b
B,0,a
B,0,b
B,1,a
B,1,b
B,2,a
B,2,b
//*/

當然也可以一次 Join 完三層條件

trace(crossJoin([["A", "B"], [0, 1, 2], ['a', 'b']]).join(“\n”));

分享到新浪微博 分享到人人网 分享到豆瓣 分享到鲜果 分享到百度空间 分享到开心网 QQ书签 分享到YAHOO! 分享到Google Google Buzz 分享到Facebook 分享到Plurk Digg delicious Technorati Twitter