Android 為我們提供了一個用來繪製圖片與動畫2D的映像庫,這兩個包分別是android.graphics.drawable 和 android.view.animation ,在這兩個包中可以找到相同的類去呈現繪圖與動畫的兩個不同面。 在這個文檔中將介紹如何在你的Android應用程式中使用這個庫。我們將討論基礎類Drawable對象如何繪圖,如何使用一對Drawable的子類,還有如何去建立圖片和動畫。
1 Drawable Drawable
是一個通用的抽象類別,它的目的是告訴你什麼東西是可以畫的。你會發現基於Drawable類擴充 出各種繪圖的類包括:BitmapDrawable ShapeDrawable PictureDrawable LayerDrawable,當然你 可以繼承它來建立你自己的繪圖類. 有三種方法可以定義和執行個體化一個Drawable,儲存一個圖片到你工程資源中,使用XML檔案來描述 Drawable屬性或者用一個正常的類去構造。下面我們將討論兩種技術(對一個有開發經驗的開發人員來說構 造並不是最新的技術)
1.1 從資源影像檔中建立 一個比較簡單的方法是添加一個圖片到你的程式中,然後通過資源檔引用這個檔案,支援的檔案類型 有PNG(首選的) JPG(可接受的)GIF(不建議),顯然這種對於顯示應用程式的表徵圖跟來說是首選的方 法,也可以用來顯示LOGO,其餘的圖片可以用在例如遊戲中。 把一個圖片資源,添加你的檔案到你工程中res/drawable/目錄中去,從這裡,你就可以引用它到你的代碼 或你的XML布局中,另一種方法,引用它也可以用資源編號,比如你選擇一個檔案只要去掉尾碼就可以了 (例如:my_image.png 引用它是就是my_image)
1.2 從XML檔案中建立 到如今,你應該比較熟悉按Android的原則去開發一個使用者介面,因此,你也應該理解了定義一個XML文 件對於對象的作用與靈活的重要性。這個理念無數次用於Drawables 如果你想建立一個Drawable對象,而這個對象並不依賴於變數或使用者的交換,把它定義到XML中去應該 是一個不錯的方法。即使你期望在你的應用程式中改變其屬性來增加使用者體驗。你應該考慮把對象放入 XML中,因為你可以隨時修改其屬性。 當你在你的XML中定義了一個Drawable,儲存這個XML檔案到你工程目錄下res/drawable目錄中,然 後通過調用Resource.getDrawable()來檢索並執行個體化,傳遞給它XML檔案中的資源ID號。 任何Drawable的子類都支援inflate這個方法,這個方法會通過XML來執行個體化你的程式。任何Drawable 都支援XML的擴充來利用特殊的XML屬性來協助定義對象的屬性,可以查看任何Drawable子類文檔來看 如何定義XML檔案 下面的XML定義了TransitionDrawable:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/image_expand">
<item android:drawable="@drawable/image_collapse">
</transition>
2 ShapeDrawable
當你想去畫一些動態二維圖片,一個ShapeDrawable對象可能會對你有很大的協助。通過ShapeDrawable,你可以通過編程畫出任何你想到的映像與樣式ShapeDrawable繼承了Drawable,所以你可以調用Drawable裡有的函數,比如視圖的背景,通過setBackgroundDrawable()設定。當然,你可以在自訂的視圖布局中畫你的圖形,因為ShapeDrawable有自己的draw()方法。你可以建立一個視圖的子類去畫ShapeDrawable在View.OnDraw()方法期間。這是一個基本的視圖擴充類去畫ShapeDrawable
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
在這個建構函式中,ShapeDrawable是定義了個ovalShape類型,然後又設定了顏色與邊界,如果你不去設定邊界,這個圖形是不會畫出來的,但是,如果你不設定顏色,它預設為黑色。通過視圖的自訂,你可以通過各種方法畫出你喜歡的東東來,下面是個簡單的例子。
CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView);
}
如果你想用XML檔案配置來取代原有布局來畫自訂的drawable,於是你自訂的Drawable類必須重載view(Context,AttributeSet)建構函式。下面是範例:
<com.example.shapedrawable.CustomDrawableView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
ShapeDrawable類(像很多其他Drawable類型在android.graphics.drawable包)允許你定義drawable公用方法的各種屬性。有些屬性你可以需要調整,包括,透明度,顏色過濾,不透明度,顏色。
3 NinePatchDrawableNinePatchDrawable 繪畫的是一個可以伸縮的位元影像映像,Android會自動調整大小來容納顯示的內容。一個例子就是NinePatch為背景,使用標準的Android按鈕,按鈕必須伸縮來容納長度變化的字元NinePatchDrawable是一個標準的PNG映像,它包括額外的1個像素的邊界,你必須儲存它尾碼為.9.png,並且保持到工程的res/drawable目錄中。這個邊界是用來確定映像的可伸縮和靜態地區。你可以在左邊和上邊的線上畫一個或多個黑色的1個像素指出可伸縮的部分(你可以需要很多可伸縮部分),它的相對位置在可伸縮部分相同,所以大的部分總是很大的。
你還有可以在映像的右邊和下邊畫一條可選的drawable地區(有效,內邊距線)。如果你的視圖對象設定NinePath為背景然後指定特殊的視圖字型,它將自行伸縮使所有的文本來適應根據右線與底部線設計好的地區(如果有的話),當然內邊距線不包括其中,Android可以使用左邊的線與上面的線來定義一個drawable地區。我們來澄清一下這兩條不同的線,左邊跟頂部的線來定義哪些映像的像素允許在伸縮時被複製。底部與右邊的線用來定義一個相對位置內的映像,視圖的內容就放入其中。下面是一個例子用NinePatch 檔案來定義個按鈕。NinePath通過左邊的線與頂部的線定義一個可伸縮的地區而底部的線與右邊的線可以定義個可畫地區,在上面的圖片中,灰色點的線定義了個映像的地區為了映像的伸縮,映像底部的粉紅色的矩形框定義了個視圖內向允許呈現的地區,如果內容不適合這個區別,它們將會將映像展開。
Draw9-path工具提供了一個非常簡單的方法去建立你的NinePath映像,. 利用WYSIWY圖形編輯器,如果你定義的地區可伸縮地區有超出圖紙範圍的危險它甚至會提出警告。下面是一個簡單的XML來示範如何在一對按鈕上添加NinePatch(NinePath圖片儲存在res/drawable/my_button_background.9.png
<Button id="@+id/tiny"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:text="Tiny"
android:textSize="8sp"
android:background="@drawable/my_button_background"/>
<Button id="@+id/big"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:text="Biiiiiiig text!"
android:textSize="30sp"
android:background="@drawable/my_button_background"/>
需要注意的是寬度與高度需要設定為wrap_content,使按鈕適合文字。
下面是兩個按鈕基於XML跟NinePath圖片的呈現,隨著按鈕通過文字大小的變化,背景映像也會去適應。
4 Tween Animation
一個tween動畫將對視圖對象中的內容進行一系列簡單的轉換(位置,大小,旋轉,透明性)。如果你有 一個文本視圖對象,你可以移動它,旋轉它,讓它變大或讓它變小,如果文字下面還有背景映像,背景 映像也會隨著檔案進行轉換。Animation package 提供了所有的類來供tween 動畫使用。 Tween 動畫定義了一個動畫指令的隊列,定義可以使用XML也可以再Android的代碼中,像定義布局一 樣,我們建議使用XML來定義,因為它具備的閱讀性,重用性,可以交換性大大超過了寫入程式碼。在下面 的例子中,我們使用XML(參考AnimationSet 類或者其它的動畫類來學習如何在代碼中定義) 動畫的指令定義了你想要發生什麼樣的轉換,當他們發生了,應該執行多長時間,轉換可以是連續的也 可以使同時的。例如,你讓常值內容從左邊移動到右邊,然後旋轉180度,或者在移動的過程中同時旋 轉,沒個轉換需要設定一些特殊的參數(開始和結束的大小尺寸的大小變化,開始和結束的旋轉角度等 等,也可以設定些基本的參數(例如,開始時間與周期),如果讓幾個轉換同時發生,可以給它們設定 相同的開始時間,如果按序列的話,計算開始時間加上其周期。 動畫的XML檔案還是在你工程中res/anim目錄,這個檔案必須包含一個根項目,可以使<alpha> <scale> <translate> <rotate> 插值元素或者是把上面的元素都放入<set>元素組中,預設情況下,所以的動畫指令都是同時發生的, 為了讓他們按序列發生,需要設定一個特殊的屬性startOffset,下面的例子會示範。 下面的ApiDemos XML檔案定義了視圖對象的伸縮功能,同時發生旋轉 。
<set android:shareInterpolator="false"><scale
android:interpolator="@android:anim/
accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="700" />
<set android:interpolator="@android:anim/decelerate_interpolator">
<scale
android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="700"
android:duration="400"
android:fillBefore="false" />
<rotate
android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="700"
android:duration="400" />
</set></set>
螢幕座標(本例中沒有使用)是(0,0)在左上方,並向右增加下去。還有許多值,像pivotX指定對象是相對自己還是父類。必須使用正確的格式來設定(”50” 是相對於父類50% “50%”相對於自己%50)您可以決定如何轉變在一段時間內適用於指定的插值,Android包括了幾個插值子類指定不同的速度曲線,例如:AccelerateInterpolator 告訴了開始比較慢,速度慢慢的變快,每個都有一個屬性值,可以用於在XML中。儲存hyperspace_jump.xml到你工程中的res/anim目錄,下面的JAVA代碼將引用它來布局一個ImageView對象。
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this,
R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
作為替代startAnimation(),你可以通過Animation.setStartTime來定義開始時間,通過view.setAnimationl來指定這個動畫關於XML的參數屬性有效標記,可以參見Available Resources中動畫的討論。
注意:你的動畫不顧後果的移動或調整大小,視圖不會去適應你的動畫而去自動調整,即使如此,動畫將會超出視圖的範圍,但不會被截斷,然而,截斷髮生在你的動畫如果超出了父類的視圖。
5 Frame Animation
建立一個連續不同的圖片的序列是傳統動畫的情境,按照指令播放,就像滾動的電影,在Android中基礎類AnimationDrawable就是專門來負責幀動畫。
雖然你可以在代碼中定義幀動畫,可以使用AnimationDrawable類的API.,它是非常簡單通過XML檔案 列齣動畫中的所有幀,像上面的動畫tween,這種類別動畫的XML檔案放入工程中的res/anim目錄。既 然這樣,指令按照周期去執行每幀動畫。 在XML檔案包含一個<animation-list>根節點元素和好幾個子節點<item>來定義每幀。一個資源分別定 義了幀的名字與幀的期間。下面為範例:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="true">
<item android:drawable="@drawable/rocket_thrust1"
android:duration="200" />
<item android:drawable="@drawable/rocket_thrust2"
android:duration="200" />
<item android:drawable="@drawable/rocket_thrust3"
android:duration="200" />
</animation-list>
這個動畫播放三個幀動畫,通過設定android:oneshot屬性為true,它將會在最後一幀停下來,如果設定 為false這個動畫將迴圈播放。這個檔案儲存到工程目錄res/anim目錄下為rocket_thrust.xml,你也 可以添加一個背景圖片到視圖中,然後開始播放。下面為範例:
AnimationDrawable rocketAnimation;
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.anim.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
rocketAnimation.start();
return true;
}
return super.onTouchEvent(event);
}
一個比較需要特別注意的是,在AnimationDrawable調用onCreate()過程中不能調用start(),這是因 為AnimationDrawable不能在不完全的視窗上運行,如果你想立即播放動畫,沒有必要的互動,你可以 再onWindowFocusChanged()方法中調用它。這樣它將成為視窗焦點。
完畢。^_^