HelloWorld for Adobe AIR for Android

5 意見 此文章的連結
前天Adobe對一般開發者開放了 (Adobe AIR for Android Developer Prerelease program )!趕緊去下載來載測試看看!

我做的第一個測試是簡單的HelloWorld,主要是跑完編譯apk檔和安裝App到手機(HTC Desire)上的流程,並稍微體驗一下效能如何。結果HelloWorld在手機上的速度表現跟電腦上幾乎一模一樣。第一個測試發現不知道為什麼stage.width/height的值在手機上會跑掉,所以我故意以手機上看起來比較正常為準,在code上做了些調整。


接下來我再做了第二個測試,因為在AIR for Android的官方文件中有聲明為了效能起見不建議使用Flex來開發(Adobe正在開發為行動裝置做最佳化的 Flex Mobile Framework, Slider),於是我想試試看用Flex來開發到底會怎樣。我把之前弄過的一個很簡單的Flex Component原封不動地丟到HTC Desire上,結果速度表現仍然是非常順暢,跟Desktop上的表現幾乎無異。而這次位置和長寬的設定倒是跟原本的設計完全一樣,都不用改。

試用 ELIPS Studio 3

2 意見 此文章的連結
ELIPS Studio是法國公司 OpenPlug 的創新開發工具,可以讓開發者用ActionScript3、Flex和Flex Builder (也支援FB4)寫code,然後編譯成行動平台的原生應用程式,目前支援的行動平台包括iPhone OS3.0 、Android 1.6、Symbian S60 3rd和Windows Mobile 6 Pro等等,想直接了解這個工具可以做到什麼程度可以參考此官方Youtube 影片,這東西被介紹得真是神。

安裝和試用的方法可參考官方網站上清楚的安裝說明,裝好以後馬上就可以直接在原本即安裝好的Flex Builder中建立、編譯、除錯ELIPS專案,也可以預覽和佈屬程式到行動裝置上。我裝完、Hello World畢後就嘗試做了的第一個ELIPS實驗,並把這個實作安裝到我的HTC Desire上,實作經錄影上傳到youtube:


試用記錄
(1) 開啟FB後會看到FB中多了ELIPS plugin的工具列,FB能夠建立ELIPS專屬的專案,可以選擇要編譯的目標平台為何。在我的電腦上編譯一次至少要花5分鐘以上 (畢竟中間也轉了好幾層)。編譯成功的話會把安裝檔全都丟到output資料夾下面,預設上,iPhone平台也會連帶編繹出source code,猜想這動作應該是為了要規避iPhone OS 4將限制第三方、跨平台語言的新規範吧。


(2) 像我這樣簡單的程式,編譯出來的SWF檔案大小是157KB,Andriod的apk安裝檔大小卻暴增到是4MB,這樣的大小好像還ok(其實在2.1的Desire上還是很不ok),但佈署到Desire上面的時候,不知道為什麼在系統中又多佔用了7MB的空間,13MB的空間對ROM很拮据的Desire來說負擔還蠻大的。這....與官方所聲明的"檔案小"的理念好像是相違背的耶 -_-"。

(3) 若用到不支援的功能,編譯時會有錯誤提示,比如現在的ELIPS版本仍不支援Flash Player10的3D座標,因此用到 rotationY語法時會有錯誤提示;但也有編譯遇到不支援的功能卻也不會有錯誤提示,變成還是要自己對照Reference

(4) ELIPS的Demo影片看起來好像很神,可是我遇到一個狀況,就是雖然 Image 元件本身的 rotation是支援的,但是為了重新調整Image物件的旋轉中心點,我把Image包在一個Canvas裡面,結果Canvas的rotation屬性目前還不被支援(如影片所示)....官方的Demo影片中甚至還有3D的CoverFlow效果,變成單單只使用Flex Framework的功能很難做出Demo影片裡面的效果,官方影片的效果好像太神了點。當然,是否可以用ELIPS額外提供的元件可以做到更多效果就沒研究了。

(5) ELIPS有另外提供他們自己的Controls元件,透過額外的元件可以做手機上特有的介面,比如手機原生的Alert視窗、聯絡人、簡訊界面等等。從sample看來,ELIPS還支援影片播放、可以抓到GPS訊號、傳送簡訊等等,這部分沒有多研究。但目前支援的視覺化的效果就沒那麼豐富了,目前支援的Flex 特效只有Move、Fade、Resize。



總結來說,目前ELIPS的成熟度還不到可以隨心所欲地用Flex來開發,必須時時注意哪些功能支援、哪些不支援,這樣子開發起來很也不輕鬆呀 -_-",如果不是為了跨平台的目的,我倒是覺得直接學目標的語言還乾脆點呢。這麼說好像有點無視這個工具和idea的創意和大膽,其實沒有,我大概有概念能夠做到這種程度已經是另一個可怕的境界了,在佩服之餘,也希望ELIPS未來很快就會有滿滿的支援囉。


相關連結:

Flex Logging Framework的使用方法

0 意見 此文章的連結
trace()是開發ActionScript的好伴侶,不過當有更高階的需求時又顯得太陽春,還好Flex有內建了一套將trace包裝得更高階的Flex Logging Framework可以用。

Flex Logging Framework主要是使用兩大元件來操作:Log和TraceTarget,TraceTarget類別繼承自Target類別,用來指定輸出的目的地為 trace(),有需要的話也可以自行繼承自target,將輸出改為輸出到其他地方,如socket。Log類別則提供方法來輸出你的log紀錄。Flex Logging Framework用起來很簡單,就直接從source code的運用情況來了解吧:

import mx.logging.LogEventLevel;
import mx.logging.Log;
import mx.logging.targets.TraceTarget;
private var _target : TraceTarget;

private function onComplete():void{
_target = new TraceTarget();
//    _target.includeCategory = true; // 包含的輸出種類
//   _target.includeDate = true; 
_target.includeTime = true;
_target.includeLevel = true;
_target.filters = ["com.*"]; // * 可用於過濾
//   _target.level = LogEventLevel.ALL;  // 以下為各顯示"層級",層級高低由高而低依序排列
//   _target.level = LogEventLevel.DEBUG; 
_target.level = LogEventLevel.INFO; //  "層級"彼此之間有上下層關係,使用info過濾的話,以下的層級都會顯示,以上不會顯示,這就是"層級"的意思
//   _target.level = LogEventLevel.WARN;
//   _target.level = LogEventLevel.ERROR;
//   _target.level = LogEventLevel.FATAL;
Log.addTarget( _target );
} 

private function sendToLog():void{
Log.getLogger("com.this1").info("Testing Log1");
Log.getLogger("com.this2").info("Testing Log2");
Log.getLogger("com.this3").info("Testing Log3");
Log.getLogger("com.this1.a").debug("Testing Log4");
Log.getLogger("com.this1.b").warn("Testing Log5");
Log.getLogger("com.this2").debug("Testing Log6");
Log.getLogger("com.this2").warn("Testing Log7");
Log.getLogger("com.this3").error("Testing Log9");
Log.getLogger("com.this3").fatal("Testing Log8");
}

修改TileList元件的ScrollBar位置

3 意見 此文章的連結
開始使用Flex開發不久,就遇到了一個不簡單的設計,就是設計師設計了一個把ScrollBar從預設的右邊移到左邊去的TileList,本以為這應該很常見,搜尋了一下竟找不到現成的改法,索性只好自己新手駕駛了。

TileList是繼承自ListBase的,而ListBase裡面可以找到verticalScrollBarhorizontalScrollBar這兩個唯一跟scrollbar有關的class property,改變這兩個物件的位置的時候,發現就可以移動scrollbar的位置了,就這麼簡單阿(?)。下面是修改後的code,簡單說明:新建的自訂元件LeftScrollBarTileList繼承自TileList,在複寫updateDisplayList方法的地方,判斷verticalScrollBar是否有被產生出來,有的話,就把它拉到最左邊,也就是verticalScrollBar.x = 0。

LeftScrollBarTileList.as
/* Copyright (c) 2009 blog.mediakid.org. All Rights Reserved. */
package {
    import mx.controls.TileList;
    public class LeftScrollBarTileList extends TileList {
        public function LeftScrollBarTileList() {
            super();
        }
        protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
                // 確認vertical是否存在
                if (verticalScrollBar && verticalScrollBar.visible){
                    verticalScrollBar.x = 0; // 移動scrollbar
                }
        }
    }
}
使用元件的主程式main.mxml
<?xml version="1.0"?>
<!--
//  Copyright (c) 2009 blog.mediakid.org. All Rights Reserved.
-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" fontSize="12" 
backgroundColor="#F0F0F0" 
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
width="450"
height="350"
>

<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
private var xml:XMLList = 
<>
<content>1</content> 
<content>2</content>
<content>3</content> 
<content>4</content>
<content>5</content> 
<content>6</content>
<content>7</content> 
<content>8</content>
<content>9</content> 
<content>10</content>
<content>11</content> 
<content>12</content>
<content>13</content>
</>;
[Bindable] private var ac : XMLListCollection = new XMLListCollection(xml);
]]>
</mx:Script>
<mx:Panel 
title="Reposition the scrollbar" 
height="300" 
width="400" >
<local:LeftScrollBarTileList
id="scroll"
dataProvider="{ac}"
xmlns:local="*" 
columnCount="2"
rowHeight="80"
borderStyle="none"
width="100%"
height="100%"
alternatingItemColors="[#FFFFFF,#CCCCCC,#999999]"
/>
</mx:Panel>
</mx:Application>

問題來了,雖然scrollbar是移到左邊了,可是TileList的右側仍然保留了預設的scrollBar的空間,事實上移動到左邊的scrollbar也壓到了一部分的TileList。

繼續trace發現,顯示"被拖曳內容"的是容器listContent,listContent上面還加了一個maskShape遮罩,所以scrollbar被移到左邊以後,這兩個物件的位置也要一併往右移動一些。只有這樣還不夠,listContent在更新位置的時候都會加上位移量leftOffset,所以leftOffset也要加上位移量,否則的話,每次一更新位置,listContent就會又跑回原來的位置。新增修改如下:
/* Copyright (c) 2009 blog.mediakid.org. All Rights Reserved. */
package {
    import mx.controls.TileList;
    public class LeftScrollBarTileList extends TileList {
        public function LeftScrollBarTileList() {
            super();
        }
        protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
                // vertical
                if (verticalScrollBar && verticalScrollBar.visible){
                    verticalScrollBar.x = 0; // 移動scrollbar
                    this.listContent.x =  verticalScrollBar.width; // 移動被拖曳內容
                    this.maskShape.x = this.listContent.x; // 移動被拖曳內容的mask
                    this.listContent.leftOffset = verticalScrollBar.width; // 設定被拖曳內容的位移量,如果是垂直的scrollbar則用topOffset
                }
        }
    }
}
效果Live Demo:

修改後的效果看似是ok的,但沒有完整的trace完全部的code,所以不曉得是否有更好的解法。而這個改法雖是以TileList為例,但我想對於所有繼承自ListBase的元件都是一樣的作法吧。以上方法同理也可以用來把預設位於下方的horizontalScrollBar改成位於上方。