原文網址:http://blog.balfes.net/?p=869
有非常多的人看過、玩過、或聽過 GMail 以及其他像 Google Wave 的應用程式。是否曾經納悶這些應用程式是怎麼做出來的?那你應該去看一下 Google Web Toolkit(GWT)。我從上個禮拜開始瘋狂地寫 GWT,我必須承認它非常有趣,應該會有很多支持它的理由。當你在開發 web 應用程式時,可以用到 Eclipse 這個 IDE 的所有好處,而且你寫的語言卻是 Java,你就會認同我了。最棒的是,你可以重頭到尾都在寫 Java,但是最後 compile 的結果卻是一個以 JavaScript 做出來美妙 web 2.0 應用程式。GWT 的 compiler 支援絕大多數 Java 語言的內容。
你可以看一下 GWT API Reference 導覽,實際感受一下 UI 可以好到什麼樣子。基礎的 widget library 也可以馬上讓你用用看;如果基礎的 widget 沒辦法滿足你,你也自己弄一些 custom widget。我覺得做的實在很棒的是 i18n 的技術(雖然我並沒有處理過很多 i18n 的東西)。講到 debug 那更是不得了,你現在可以輕鬆在 Eclipse 用正統的 debugger 來開發、debug 你的 JavaScript 應用程式。GWT Compiler 只產生一些 JavaScript 跟 HTML 檔,與其他公開的 resource(例如 CSS、圖檔)分開。在 deploy 時,你需要做的就是把這些東西放到你的 web server 上。
為甚麼 GWT 可以這麼酷咧?我想關鍵點在於它會吸引 Java 開發者,而且在轉成 JavaScript 的時候還會幫你作最佳化。你會得到一堆混淆過後的 JavaScript 檔案,且已經針對主要的 browser 作最佳化—這些常常是你得先知道怎麼作,然後常常還得自己手工處理的煩人事。你還可以把你做的東西掛進 GWT SDK 當中。為自己的產品及開發人員,建立自己的 service、UI 元件。還有還有,GWT 是 open source 的,你可以在 Apache 2.0 license 的規範下使用 & 修改它。
我相信我們會聽到更多 GWT 的東東,我也希望聽到關於這個 Web 2.0 開發方式的不同意見。
========
原文下面還有一堆 comment,就懶得翻譯了 XD
作者後來又 po 了一篇補刀的文章,也可以順便看看
2009年11月6日 星期五
2009年10月7日 星期三
GWT Animation 再探
在〈GWT Animation 初探〉當中,程式已經能讓畫面看起來有動畫的效果,「表面上」要怎麼使用 Animation 是沒有問題了;不過這樣子有些無趣,還是要殺進去 Animation 來瞭解這一切背後的內幕(?)。
起點當然是 Animation.run(),沒有呼叫這個 method,是不會有什麼反應的。run() 有兩個,run(int duration, double startTime) 的 duration 是 Animation 預計持續作用的時間;startTime 是預計執行的時間。為甚麼用 startTime 的 data type 是 double 呢?這點在 Animation 不算是有用到的 Duration.elapsedMillis() 可以找到答案:
回到 run(int, double) 的內容,關鍵點在於下面這段
在開始跟結束的部份比較緩和,或許這樣比較符合人類視覺觀點?總之,這是為甚麼 Animation 的 javadoc 會說「at a non-fixed frame rate」了。(順帶提一點,相同的 duration,呼叫 onUpdate() 的次數應該會一樣,但是 progress 值會有差異。這應該是 Timer 先天上無法很精準的缺陷?)
看到這邊,Animation 應該可以說沒有秘密了。剩下來就是如何運用的問題了...... [遠目]
起點當然是 Animation.run(),沒有呼叫這個 method,是不會有什麼反應的。run() 有兩個,run(int duration, double startTime) 的 duration 是 Animation 預計持續作用的時間;startTime 是預計執行的時間。為甚麼用 startTime 的 data type 是 double 呢?這點在 Animation 不算是有用到的 Duration.elapsedMillis() 可以找到答案:
Returns the same result as System#currentTimeMillis(), but as a double. Because emulated long math is significantly slower than doubles in web mode, this method is to be preferred.因為在瀏覽器上頭,使用 double 處理起來比模擬 long 還要快得多(btw... 為甚麼 Animation 只用了 Duration.currentTimeMillis() 取得時間,而沒有用 Duration.elapsedMillis() 去計算時間差,這我一直想不透 XD)。另一個 run(int duration) 其實還是呼叫 run(int, double),只是自動以當下時間傳給 startTime。
回到 run(int, double) 的內容,關鍵點在於下面這段
if (animations == null) {
animations = new ArrayList(); //point-A
animationTimer = new Timer() {
@Override
public void run() {
updateAnimations();
}
};
}
animations.add(this);
這邊要回頭看一下 Animation 的資料結構。講起來有點饒舌。大致上來說,Animation 有一些 static 的 field 跟 method,目的是統一處理系統當中所有的 Animation object(程式碼 point-A)。這裡也可以看到,其實 Animation 裡頭是用 Timer 來實做的。Timer 的細節得先跳過,這裡只要知道看到 animationTime.schedule(int delayMillis) 就表示隔了 delayMillis 個 ms 就會執行 updateAnimations() 的內容,而 updateAnimations() 會呼叫 update()。那麼,勢必有需要好好看一下 update() 的內容:private boolean update(double curTime) {
boolean finished = curTime >= startTime + duration;
if (started && !finished) {
// Animation is in progress.
double progress = (curTime - startTime) / duration;
onUpdate(interpolate(progress));
return false;
}
if (!started && curTime >= startTime) {
// Start the animation.
started = true;
onStart();
// Intentional fall through to possibly end the animation.
}
if (finished) {
// Animation is complete.
onComplete();
started = false;
running = false;
return true;
}
return false;
}
裡頭依照不同的狀況,呼叫了 onUpdate(), onStart() 跟 onComplete()。嗯?為甚麼只有 onUpdate() 是 abstract 的呢?因為這兩個到最後還是去呼叫 onUpdate(),progress 的值給 0 表示剛開始、給 1 表示結束。接下來就是最詭異的部份啦,傳給 onUpdate() 的數值,居然還要經過 interpolate() 的計算,這又是為甚麼呢?根據 javadoc 的說法:Interpolate the linear progress into a more natural easing function.看個對照圖可能比較好懂:
在開始跟結束的部份比較緩和,或許這樣比較符合人類視覺觀點?總之,這是為甚麼 Animation 的 javadoc 會說「at a non-fixed frame rate」了。(順帶提一點,相同的 duration,呼叫 onUpdate() 的次數應該會一樣,但是 progress 值會有差異。這應該是 Timer 先天上無法很精準的缺陷?)
看到這邊,Animation 應該可以說沒有秘密了。剩下來就是如何運用的問題了...... [遠目]
2009年10月5日 星期一
GWT Animation 初探
Animation 是 GWT 內的一個 class,名字取的很美妙,實際上是在做什麼的呢? GWT 的 showcase 給了一個示範,不過裡頭的程式碼實在有點古怪,姑且直接來看 1.6 版的 API doc 怎麼說。
只要 new 一個 HelloAnimation,然後加到 RootPanel 上頭去,就會看「Hello Animation」從畫面左邊跑到右邊。(至於最後「Hello Animation」突然換行的狀況,先跳過... XD)
裡頭兩個 class 分別負責兩件事情。HelloAnimation 負責畫面顯示的部份,直接 extends AbsolutePanel,搭配 AbsolutePanel.setWidgetPosition() 就可以很快速地設定 widget 的位置,這樣在上頭的東西「動」起來就相對方便。playOneFrame() 這個 method 就是在處理這件事情,至於 progress 這個參數的作用,就必須回到 Animation(也就是範例程式裡頭的 Player)才能說明。
Player 這個 class 其實很簡單,extends Animation 之後,只有一個 method 必須實作,就是 onUpdate()。這個 method 就是 API 提到的效果,當 Player 起作用的時候,onUpdate() 就會持續地被呼叫、並且給予不同的參數 progress 值,值域介於 0~1 之間,會隨著時間會越來越大,乘上 100 就是完成度啦,因為實際負責「動」的物件是 HelloAnimation,所以在呼叫 HelloAnimation.playOneFrame() 時候就原封不動地傳進去。這個參數在製作像動畫這種東西時,就很方便,因為 Animation 幫你算好 progress,不用自己動手。像這個例子當中,「Hello Animation」要在指定的時間內橫越指定的寬度,但是在撰寫 playOneFrame() 時完全不用理會「指定的時間」有多長,只要把寬度乘上 progress 就解決了。現在動畫的長度是五秒鐘(程式碼 point-A),要改成兩倍慢 or 兩倍快,就只要在 player.run() 時給 10 秒 or 2.5 秒就可以了。
看到這裡,是不是覺得 GWT 設計的很好、使用起來很簡單呢? [奸笑]
至於 Animation 的細節,我們下次再談(初探嘛...)
An Animation is a continuous event that updates progressively over time at a non-fixed frame rate.哈哈... 根本就是騙人的,哪來什麼動畫 [笑]。簡單地說「Animation 是一個會持續要求 update 動作的物件。而間隔的時間是不固定的。」阿?這什麼鬼?還是用程式碼來說明好了...
import com.google.gwt.animation.client.Animation;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Label;
public class HelloAnimation extends AbsolutePanel{
private Label hello = new Label("Hello Animation");
private final int WIDTH = 800;
private final int HEIGHT = 200;
public HelloAnimation(){
this.setPixelSize(WIDTH, HEIGHT);
this.add(hello); //要先加上去,才有辦法移動
Player player = new Player(this);
player.run(5*1000); //point-A
}
public void playOneFrame(double progress){
this.setWidgetPosition(hello, (int)(WIDTH*progress), HEIGHT/2);
}
}
class Player extends Animation{
HelloAnimation target;
public Player(HelloAnimation t){
target = t;
}
@Override
protected void onUpdate(double progress) {
target.playOneFrame(progress);
}
}
只要 new 一個 HelloAnimation,然後加到 RootPanel 上頭去,就會看「Hello Animation」從畫面左邊跑到右邊。(至於最後「Hello Animation」突然換行的狀況,先跳過... XD)
裡頭兩個 class 分別負責兩件事情。HelloAnimation 負責畫面顯示的部份,直接 extends AbsolutePanel,搭配 AbsolutePanel.setWidgetPosition() 就可以很快速地設定 widget 的位置,這樣在上頭的東西「動」起來就相對方便。playOneFrame() 這個 method 就是在處理這件事情,至於 progress 這個參數的作用,就必須回到 Animation(也就是範例程式裡頭的 Player)才能說明。
Player 這個 class 其實很簡單,extends Animation 之後,只有一個 method 必須實作,就是 onUpdate()。這個 method 就是 API 提到的效果,當 Player 起作用的時候,onUpdate() 就會持續地被呼叫、並且給予不同的參數 progress 值,值域介於 0~1 之間,會隨著時間會越來越大,乘上 100 就是完成度啦,因為實際負責「動」的物件是 HelloAnimation,所以在呼叫 HelloAnimation.playOneFrame() 時候就原封不動地傳進去。這個參數在製作像動畫這種東西時,就很方便,因為 Animation 幫你算好 progress,不用自己動手。像這個例子當中,「Hello Animation」要在指定的時間內橫越指定的寬度,但是在撰寫 playOneFrame() 時完全不用理會「指定的時間」有多長,只要把寬度乘上 progress 就解決了。現在動畫的長度是五秒鐘(程式碼 point-A),要改成兩倍慢 or 兩倍快,就只要在 player.run() 時給 10 秒 or 2.5 秒就可以了。
看到這裡,是不是覺得 GWT 設計的很好、使用起來很簡單呢? [奸笑]
至於 Animation 的細節,我們下次再談(初探嘛...)
訂閱:
文章 (Atom)