典型的應用程序生存期由一些狀態組成:數據輸入表單、結果界面、含有各種圖像的相簿、含有項目的購物車等等。通常,應用程序執行繁 重的任務使用戶在這些不同的界面中切換:新的界面替代原來的表單,突然在屏幕中彈出結果,圖形和 GUI 對象時而從屏幕中跳出。一般而言 ,各個當前 UI 屏幕都會在操作完成後關閉,然後新的屏幕將取代它的位置。
HTML 應用程序就是一個很好的例子:在某個頁面中填寫一些數據,單擊提交(Submit)按鈕,原頁面將消除,取而代之的是另一個全新的 用戶界面。然後,您將仔細審視這個新界面,考慮自己應該做的事情並找到新的提交按鈕。
如果應用程序在這些不同的應用程序狀態之間創建一個更具邏輯性的流程,並為用戶帶來各個新用戶界面(UI)會不會更好呢?如果用戶不 用重新打量各個新用戶界面,而是采用應用程序的流程化方式會怎麼樣呢?< /p>
這正是動畫轉換的內容:使應用程序用戶界面的轉換具有動畫效果,從而在這些狀態之間創建一個無縫的流程。通過幫助用戶理解用戶界面 之間的組合,轉換可以幫助保證用戶連接到程序。
當然,這個問題對開發人員而言意味著更多的工作。讓應用程序消除一個界面並顯示下一個界面是處理這種問題的最直觀的方法。在界面之 間運行某種動畫通常要求理解動畫過程,然後編寫一大堆自定義代碼使界面上的元素具有動畫效果。
這正是編寫 動畫轉換 庫的原因:從根本上簡化應用程序狀態之間動畫的流程,執行合理的默認動畫,以及讓您專注於編寫應用程序代碼而 不是動畫代碼。
演示時間
我們來看一個簡單的演示應用程序 FieldsOfText。該應用程序將模擬一個常見的功能(別處可能也有),用戶可以請求 GUI 展開自己並提 供更多文本字段。比如說,我將使用一個類似於此的對話框將 至關重要的卡通畫 上傳到 我的 java.net 博客。應用程序開始只有一個文本字 段,但是通過單擊 More 或者 Less 按鈕可以增加或減少所顯示的文本字段數量。
界面底部也有一個提交按鈕,因此此類應用程序通常都有提交按鈕。此處的按鈕實際上並沒有執行任何任務,不過它和其他用戶界面元素的 作用一樣,都是顯示動畫轉換的過程。
以下是用於顯示 GUI 的代碼:
// Add the More/Less buttons container
add(moreOrLess);
// Next, add the proper number of text fields
for (int i = 0; i < numFields; ++i) {
add(textFields[i]);
}
// Finally, add the Submit button at the bottom
add(submitPanel);
在這段代碼中, moreOrLess 組件是一個面板,用於保存 More 和 Less 按鈕。 textFields[] 數組用於保存將要填充到 GUI 中的各種不 同的文本字段。而 numFields 表示我們希望此時顯示的數量。 submitPanel 組件是一個面板,用於保存提交按鈕。
下面是提供的用戶的基本用戶界面:
圖 1. 應用程序的初始界面
當用戶單擊 More 按鈕,原文本字段下面將增加一個文本字段,如下圖所示:
圖 2. 用戶單擊 More 按鈕之後的應用程序界面
當用戶單擊 Less 按鈕,最下面的文本字段將消失,用戶界面將回到圖 1。
在典型的應用程序中,上述步驟可能是先消除原始窗口然後再顯示新的用戶界面。與此不同,動畫轉換庫將平穩地在這些狀態之間切換。它 將淡入或淡出將要消除或出現的組件(比如說一個文本字段),而這些組件可能位於不同的位置(如提交按鈕)。舉例說明,圖 3 顯示了在前 兩個界面之間轉換時的用戶界面:
圖 3. 前兩個界面之間的動畫轉換
在圖 3 中,我們可以看到第二個文本字段的淡出效果,而提交按鈕將向下移動。
如果要查看動態效果,可以下載我所創建的視頻剪輯( QuickTime 或 MPEG-4 格式)查看轉換效果。< /p>
接下來,我們將了解演示應用程序如何實現這種轉換效果。
動畫轉換:API
從最基本的角度而言,這個庫由一個 ScreenTransition 對象(負責建立和運行動畫)和一個 TransitionTarget 接口(代碼需要實現這個 接口)組成。
ScreenTransition
建立動畫的代碼將使用參數創建這個對象。它的構造函數類似以下形式:
public void ScreenTransition(JComponent transitionContainer,
TransitionTarget target,
Animator animator)
此處:
transitionContainer 容器的子類將在轉換過程中實現動畫效果。
target 是 TransitionTarget 的一個實現,它定義了 setupNextScreen() 方法。該方法用於定義轉換界面的GUI。
animator 定義實際動畫的參數,比如說持續時間。關於 Animator 的完整描述不在本文討論范圍之內。有關更多信息,請參閱 參考資料 中的 Timing Gramework 參考指南。
要在應用程序中運行轉換,可隨時調用 start() 方法:
public void start()
調用此方法時, ScreenTransition 將建立運行轉換所需的一切條件,然後將運行轉換。
TransitionTarget
TransitionTarget 一是個簡單的接口,它只含有一個方法:
public void setupNextScreen()
代碼需要實現這個方法並建立轉換容器 GUI。這樣,當方法完成時,應用程序將處於轉換完成時的狀態。
API 的使用
接下來,我們來了解一下 FieldsOfText 應用程序是如何使用這個 API 的。
首先,我們建立了一個 Animator 運行後半程的轉換動畫。我們將在轉換起始時刻添加一些加速和減速。這種加速/減速行為並不是必需的 ,但是一般而言非線性轉換的動畫效果會好一些( Smooth Moves 這篇文章有詳細的解釋)。
Animator animator = new Animator(500);
animator.setAcceleration(.2f);
animator.setDeceleration(.2f);
然後,我們建立 ScreenTransition 對象使用主(main) JComponent 對象作為轉換的一個容器,以及 TransitionTarget 對象(它實現了 setupNextScreen() 接口)和之前建立的 animator:
ScreenTransition transition =
new ScreenTransition(this, this, animator);
當用戶單擊 More 或 Less 按鈕時, actionPerformed() 方法將觸發轉換:
public void actionPerformed(ActionEvent ae) {
boolean changed = false;
if (ae.getSource().equals(moreButton)) {
if (numFields < MAX_FIELDS) {
numFields++;
changed = true;
}
} else if (ae.getSource().equals(lessButton)) {
if (numFields > 1) {
numFields--;
changed = true;
}
}
if (changed) {
transition.start();
}
}
最後,我們在 setupNextScreen() 方法處理來自 ScreenTransition 的回調:
public void setupNextScreen() {
// First, clear out the previous GUI and start from scratch
removeAll();
// Add the More/Less buttons
add(moreOrLess);
// Next, add the proper number of text fields
for (int i = 0; i < numFields; ++i) {
add(textFields[i]);
}
// Finally, add the Submit button at the bottom
add(submit);
}
注意,這段代碼與之前的 GUI 建立代碼幾乎相同;惟一的不同之處就是首先調用了 removeAll() 消除以前的 GUI。這段代碼的全部作用就 是為應用程序的合適界面建立 GUI。
就是這樣!應用程序還需要一些代碼處理其他任務,比如說建立 JFrame、在背景中繪出藍色的斜線條,以及建立與組件和布局管理有關的 一些詳細信息。但是應用程序的大部分實際邏輯,特別是與動畫轉換有關的代碼都已經在上面列出了。
那麼它是如何工作的呢?
工作原理
當您的代碼調用 start() 方法時, ScreenTransition 將計算出轉換容器中的組件的當前屬性,比如說位置和大小。然後,應用程序將調 用 setupNextScreen() 方法,用於建立下一個界面的 GUI。最後,應用程序將計算出剛才建立的界面中的組件的屬性。
注意,系統期望轉換容器在適當的時候共享組件,而不是使用完全不同的組件表示相同的事物。因此,如果轉換前後的兩個界面都有一個提 交按鈕,那麼您可能希望在兩種情況下都使用相同的 JButton 對象以獲得期望的效果。否則,系統將認為前一個按鈕消失而新的按鈕出現取代 它。這並沒有特別的技巧;如果希望在界面之間共享組件,那麼應該使用在界面中使用相同的組件。
在這種情況下, ScreenTransition 將含有兩個界面中的組件的所有信息:哪個組件在哪個界面中、組件的位置、組件的大小等等。因此, 我們便可以計算出兩個界面中的組件將發生哪些變化。在界面之間發生變化的任何組件都將經歷以下三種轉換之一:
出現:第一個界面沒有該組件,而第二個界面含有該組件。
消失:第一個界面含有該組件,而第二個界面沒有該組件。
變化:兩個界面都有該組件,但是組件將在兩個界面之間出現改變。
然後, ScreenTransition 將為各個組件選擇合適的轉換效果:
出現:組件將在轉換過程中淡入顯示。
消失:組件將在轉換過程中淡出顯示。
變化:組件將在轉換過程中移動或按比例縮放。
擁有所有這些信息之後, ScreenTransition 將開始運行動畫,根據與各個組件相關的轉換效果修改該組件的外觀。
當轉換完成時,控制將返回應用程序。同時,之前應用程序在 setupNextScreen() 中建立的 GUI 將處於活動狀態。
自定義效果
應用程序將使用內建的轉換效果處理一些常見的情況。通常,淡入淡出和移動/調整大小是組件的默認行為。但是,需要廣泛使用動畫轉換 的應用程序可能更希望為特定的組件或在特定的情況下創建自定義效果。比如說,< 您可能希望組件以拉近或拉遠的方式消失,或滑出界面 。
庫中所編寫的轉換效果是可擴展的。因此,我們可以創建效果並在系統中注冊該效果,然後在應用程序中插入自己的效果。這些效果與組件 和轉換類型相關(出現、消失或變化)。當 ScreenTransition 搜索合適的效果應用於特定的組件和轉換類型時,它將使用自定義的效果(如 果已注冊)。
編寫自定義效果其實相當簡單:您只需重寫兩三個方法用於在轉換過程中處理建立、消除和繪圖之類的功能即可。有關如何編寫自定義效果 的內容不在本文的討論范圍之內。但是,如果對此特性感興趣,可以閱讀 這本書的網站 上的“第 18 章:動畫轉換”,其中展示了自定義效 果的代碼和實例。
小技巧
我們可以在動畫轉換中使用各種小技巧實現庫所需的功能和性能。關於這些技巧的完整介紹,請參閱代碼和圖書獲得詳細信息。比如說,動 畫轉換庫在轉換完成前處理第二個界面的方式就很有趣。還有,動畫轉換庫處理兩個界面中的布局的方式也值得一看。同時,動畫轉換庫還可 以在轉換過程中快速顯示組件的圖像快照,從而支持更佳的性能和復雜動畫。
未來的工作
動畫轉換庫這個項目還在發展之中。我希望負責該項目的開發人員可以繼續重新定義其 API 並增強其功能。與此同時,動畫轉換庫的實用 性是毋庸質疑的。它應該讓開發人員能夠方便且無縫地連接到不同的應用程序狀態,並為他們的用戶提供生動的用戶體驗。
嘗試使用動畫轉換庫並將意見發送給我。