Android 提供一個定制的 2D 圖形庫,用來繪制圖形圖像和制作動畫。你將從 android.graphics.drawable 和 android.view.animation 包中找到這些通用類。
本文簡單介紹如何在 Android 應用程序中進行畫圖。我們將討論使用 Drawable 對象畫圖的基礎知識,如何使用幾個 Drawable 子類,以及如何創建動畫,一個圖形的補間動畫或者一系列圖形的連續動畫(就像電影膠卷一樣)。
可繪制物 Drawables
一個 Drawable 是一個“某些可以被繪制的物體”的一般抽象。你將發現這個 Drawable 類擴展了多種具體可繪制圖形類,包括 BitmapDrawable , ShapeDrawable , PictureDrawable , LayerDrawable , 等等。 當然,你還可以擴展這些類來定義你自己的具有獨特行為的可繪制對象。
有三種方式來定義和實例化一個 Drawable :使用一個保存在你的項目資源中的圖像;使用一個定義了 Drawable 屬性的 XML 文件;或者使用通常的類構造函數。下面,我們將挨個討論前面兩種方法(對于一個經驗豐富的開發人員而言,使用構造函數沒什么新意)。
從資源圖像中創建 Creating from resource images
一個為你的應用程序增加圖形的簡單方法是通過引用項目資源中的一個圖片文件。支持的圖片文件格式有 PNG (推薦的), JPG (可接受的)和 GIF (不鼓勵的)。 這個技術將顯然推薦使用在應用程序圖標, logo ,或者其它類似使用于游戲中的圖形。
為了使用一個圖片資源,只要把你的文件添加到你項目的 res/drawable/ 目錄即可。從那里,你可以在代碼或 XML 布局中進行引用。任何一種方式,都是通過資源 ID 來引用,資源 ID 是不帶擴展后綴的文件名(比如, my_image.png 通過 my_image 來引用 ) 。
注意 : 圖像資源被放在 res/drawable / 里。也許會通過 aapt 工具進行無損圖像壓縮而被自動優化。比如,一個不需要多于 256 色的真彩色 PNG 圖片可能會被轉換成一個帶有調色板的 8 位 PNG 。這產生了相同質量但占用更少內存的圖片。因此需要意識到該目錄下的二進制圖像可能會在編譯期間被改變。如果你想以比特流讀取一個圖片并轉換為一個位圖,那么需要把你的圖片文件放在 res/raw/ 目錄,這里的文件不會被優化。
示例代碼 Example code
下面的代碼片斷說明了如何構造一個 ImageView ,從 drawable 資源中使用并添加到布局中。
LinearLayout mLinearLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a LinearLayout in which to add the ImageView
mLinearLayout = new LinearLayout(this);
// Instantiate an ImageView and define its properties
ImageView i = new ImageView(this);
i.setImageResource(R.drawable.my_image);
i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions
i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
// Add the ImageView to the layout and set the layout as the content view
mLinearLayout.addView(i);
setContentView(mLinearLayout);
}
在其它情況下,你可能想把你的圖片資源當作一個可繪制 Drawable 對象。為此,你可以這樣做 :
Resources res = mContext.getResources();
Drawable myImage = res.getDrawable(R.drawable.my_image);
注意 : 每個你項目里的唯一資源只能維護一個狀態,而無論你為它實例化了多少個不同對象。比如,如果你從相同的圖像資源實例化兩個可繪制對象,然后改變其中之一的屬性(比如 alpha ),那它也將作用于另一個。所以當處理一個圖片資源的多個實例時,你應該實施一個 tween animation ,而不是直接轉換這個可繪制對象。
示例 XML
下面的 XML 片斷顯示了如何添加一個可繪制資源到一個 XML 布局中的 ImageView 里(為了有趣些,添加一些紅色渲染)。
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#55ff0000"
android:src="@drawable/my_image"/>
更多關于使用項目資源的信息,請閱讀資源和資產 Resources and Assets 。
從資源 XML 中創建 Creating from resource XML
到目前為止,你應該對 Android 用戶界面 User Interface 的 開發原理比較熟悉。 因此,你應該了解在 XML 中定義對象所固有的能力和靈活性。這個理念從視圖延伸到可繪制對象。如果你想創建一個可繪制( Drawable )對象,而它并不初始依賴于你代碼中的變量或者用戶交互,那么在 XML 里面定義它是個好的選擇。即便你預期這個可繪制對象在用戶使用你的應用程序時將會改變其屬性,你也應該考慮在 XML 里面定義它,因為一旦被實例化后,你就可以修改它的屬性。
一旦你在 XML 中定義了你的可繪制對象,把這個文件保存到你項目中的 res/drawable/ 目錄下。然后,通過傳遞資源 ID 參數調用 Resources.getDrawable() 獲取并實例化這個對象。 (參見 example below . )
任何支持 inflate() 方法的可繪制對象( Drawable )子類可以在 XML 里定義并由你的應用程序實例化。每個支持 XML 擴充的可繪制對象利用特定的 XML 屬性來幫助定義對象屬性(參見類參考了解這些屬性)。查閱每個可繪制對象子類的類描述文檔,以獲知如何在 XML 中定義它。
例子 Example
下面是一些定義了一個 TransitionDrawable 對象的 XML 語句:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/image_expand">
<item android:drawable="@drawable/image_collapse">
</transition>
當把這個 XML 保存為 res/drawable/expand_collapse.xml 文件后,下面的代碼將用來實例化它并把它設置為一個 ImageView 的內容:
Resources res = mContext.getResources();
TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.expand_collapse);
ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);
然后通過下面的方法讓這個 transition 運轉起來(每 1 秒轉變一次):
transition.startTransition(1000);
請參考上面所列的可繪制對象( Drawable )類以了解更多它們所支持的 XML 屬性。
可繪制形狀 ShapeDrawable
當你想動態的畫一些二維圖形時, ShapeDrawable 對象可能會滿足你的要求。 通過一個 ShapeDrawable ,你可以繪制原始圖形和以任何想象得到的方式設計它們。
ShapeDrawable 是 Drawable 的一個擴展類,因此你能使用在任何可用 Drawable 的地方 - 也許是視圖背景,用 setBackgroundDrawable() 方法來設置。當然,你還能以它自己的視圖來繪制圖形,并添加到你的布局中只要你樂意。因為 ShapeDrawable 有它自己的 draw() 方法,你可以創建一個視圖子類在 View.onDraw() 方法中繪制這個 ShapeDrawable 。 下面這個視圖類的一個基本擴展就是這么做的,把 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 布局中而不是活動中繪制這個自定義可繪制對象,那么這個 CustomDrawable 類必須重寫 View(Context, AttributeSet) 構造函數,這個當通過 XML 擴充來實例化一個視圖時被調用。然后為這個 XML 添加一個 CustomDrawable 元素,如下:
<com.example.shapedrawable.CustomDrawableView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
這個 ShapeDrawable 類(像很多其他在 android.graphics.drawable 包中的可繪制對象類型一樣)允許你通過公共的方法來定義這個可繪制對象的各種屬性。有一些屬性,你可能會做一些調整,比如 alpha 透明度,顏色過濾器,抖動,模糊度和顏色。
可繪制九宮格
一個 NinePatchDrawable 圖形是一個可拉伸位圖圖像, Android 會自動調整來容納視圖的內容,你可以用來作為背景。一個使用九宮格的例子是 Android 按鈕背景 - 按鈕必須延伸以適應各種長度的字符串。一個九宮格可繪制對象是一個標準的 PNG 圖像,并包含一個附加的單像素寬的邊界。它必須以擴展名 .9.png 保存,并存放到 res/drawable/ 目錄。
這個邊界用來定義這個圖像的可拉伸和靜態區域。通過在邊界的左邊和上面部分繪畫單像素寬的一個或多條黑線來指示一個可拉伸區。(你能有任意多的可拉伸區)。這些可拉伸區的相對尺寸保持一樣,因此最大的區域總是保持最大。
你也可以通過在右邊和下面畫線來定義這個圖片(事實上,這些填充線)的一個可選的可繪制區。如果一個視圖對象設置這個九宮格為其背景然后指定這個視圖的文本,它將自我調整以使得文本適應在剛才通過右邊和下面的畫線指定的區域里面(如果被包含進來)。如果這些填充線未被包含, Android 使用左邊和上面的線來定義可繪制區域。
為了闡明不同線的區別,左邊和上面定義了哪些圖像像素允許被復制來拉伸這個圖像。下面和右邊的線則定義了這個圖像中的相對區域,這個區域可允許視圖內容顯示于其中。
下面是一個用來定義一個按鈕的九宮格文件例子:
這個九宮格通過左邊和上面的線條定義了一個可拉伸區域以及通過下面和右邊的線條定義了一個可繪制區域。在圖中上半部分,灰色的虛線標示了可以被復制來拉伸圖像的區域。而下半部分的粉紅虛線框標示了允許顯示視圖內容的區域。如果內容不能適應這個區域,那么這個圖像將被拉伸來適應它。
Draw 9-patch 工具提供了一個非常方便的方法來創建你的九宮格圖像,使用一個所見即所得的圖像編輯器。它甚至會在你的可拉伸區域會產生人工痕跡時(復制像素的副效果)提出告警。
示例 XMLExample XML
下面是一些示例布局 XML 來說明怎么添加一個九宮格圖像到幾個按鈕中。(這個九宮格圖像被保存為 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 和上面顯示的九宮格圖像進行繪制。注意按鈕的高度和寬度如何根據文本大小進行相應調整,以及背景圖片自動拉伸來容納它。
補間動畫 Tween Animation
一個補間動畫可以在視圖對象的內容上執行一系列的簡單變換(位置,尺寸,旋轉和透明度)。因此,如果你有一個文本視圖 TextView 對象,你可以移動,旋轉,擴展或者收縮這個文本。如果它有一個背景圖像,也將隨著文本一起變換。動畫包 animation package 提供了所有補間動畫需要使用的類。
一系列動畫指令定義了這個補間動畫,通過 XML 或者代碼。就像定義一個布局一樣, XML 文件是推薦使用的方法,因為它比硬編碼這個動畫要更容易閱讀,可復用和可交換。在下面的例子中,我們使用 XML 。(為了學習更多關于在你的應用程序中定義一個動畫方面的知識,請參考 AnimationSet 類和其他 Animation 子類。)
動畫指令定義你想要發生的變換,什么時候發生以及多長時間。變換可以是順序的或者是同時發生的 - 比如,你可以讓一個 TextView 的內容從左到右移動,然后旋轉 180 度,或者你讓它同時移動和旋轉。每個變換采用一組特定參數(尺寸變化的起動以及結束尺寸,旋轉的起動和結束角度,等等),和一組通用參數(比如,起動時間和持續時間)。要使若干變換同時發生,可以為它們設定相同的起動時間;要讓它們順序發生,計算起動時間為前置變換起動時間加上持續時間。
這個動畫 XML 文件歸屬于 res/anim/ 目錄。該文件必須有一個單獨的根元素:這將會是一個單獨的 <alpha> , <scale> , <translate> , <rotate> , 插值器( interpolator )元素 , 或包含這些元素組的 <set> 元素(可能含有另一個 <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) ,向下和向右時坐標值增加。
margin: 0cm 0cm 12pt; line
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
