簡易版 3D Banner 效果

20 11月 2011 In: ActionScript3, Flash

大家好,我是奶綠茶
最近學生問起了一個 3D 的 Banner 效果要如何製作
寫了一個簡單的 Demo, 程式碼也很短,
只用到 TweenMax , 和 FlashPlayer10 的 3D 即可做到

import com.greensock.TweenMax;
var container:Sprite = new Sprite();
container.x = stage.stageWidth >> 1;
addChild( container );
addEventListener(Event.ENTER_FRAME , enterFrameHandler);
 
var back:MovieClip = new Back_mc;
back.x = stage.stageWidth >>1;
back.y = 40;
back.visible=false;
 
addChild( back );
 
back.addEventListener(MouseEvent.CLICK , function(){
showBack(false);
});
 
(function () {
for(var i:int = 0 ; i 90 ){
container.visible = false;
back.visible = true;
}
}
}else{
_update = function () {
if( container.rotationY < 90 ){
container.visible = true;
back.visible = false;
}
}
_onComplete = function () {
addEventListener(Event.ENTER_FRAME , enterFrameHandler);
}
 
}
TweenMax.to( container , .7 , {
rotationY:_targetV,
onUpdate:_update,
onComplete:_onComplete
});
TweenMax.to( back , .7 , { rotationY:_targetV });
}
 
function enterFrameHandler (e:Event):void {
var _value:Number = stage.stageWidth*.5 - mouseX;
_value *= 0.05;
container.rotationY += (_value - container.rotationY)/10;
}


SourceCode

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

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

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

iPhone开发讲座第一讲 iOS简介

15 11月 2011 In: iOS

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

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

自訂 Flex 滑鼠游標實體

5 11月 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 11月 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