圖片資源:Drawable
在學習 View 的時候,我們學習過 ImageView。它除了在 xml 的 src 屬性中設置圖片之外,還可以通過setImageDrawable( )
和setBackgroundDrawable( )
兩個 API 設置圖片資源。這兩個 API 都包含一個關鍵詞——Drawable,那么我們這一節就來看看,Drawable 到底是個什么東西。
1. Drawable 是什么
Drawable 從字面上理解就是一個可繪制的圖形對象,最簡單的例子就是常用的 Bitmap 對象,在 Android 中可以通過一個 BitmapDrawable 對象來呈現。
每一個 Drawable 內部都保存了一個“res/drawable”目錄下的私有文件,比如我們會將不同分辨率的圖片資源存儲在“mdpi”、“hdpi”、“xhdpi”以及“xxhdpi”里面,這些目錄是在創建工程的時候 Android Studio 自動幫我們生成好的,然后在運行的時候系統會根據當前的設備類型自動選擇一種合適的 bitmap 圖片資源為我們所用。
2. 為 View 設置 Drawable
在 xml 中使用是很最常見的用法,而且我們一直在用,回顧一下我們設置的圖片資源,比如一個 TextView 的背景樣式,通常會這么寫:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text"
android:text="@string/hello_world" />
其中 background 屬性的值就是一個 Drawable 對象,同樣我們可以在 Java 代碼中給 View 設置一個 Drawable 參數:
ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setImageResource(R.drawable.image);
3. 加載 Bitmap 和 Drawable
Android 提供了一個Bitmap
類來處理 bitmap 圖片相關的功能,接下來我們看看如何通過 Java 代碼創建一個 Bitmap 并將 Bitmap 轉換成 Drawable:
?AssetManager manager = getAssets();
?// 從 assets 中讀取 bitmap
?InputStream open = null;
?try {
?open = manager.open("imooc.png");
?Bitmap bitmap = BitmapFactory.decodeStream(open);
?// 給 imageView 設置 bitmap 對象
?ImageView view = (ImageView) findViewById(R.id.imageView1);
?view.setImageBitmap(bitmap);
?} catch (IOException e) {
?e.printStackTrace();
?} finally {
?if (open != null) {
?try {
?open.close();
?} catch (IOException e) {
?e.printStackTrace();
?}
?}
除此之外,還可以從“res/drawable”文件夾中獲取 Drawable,并在代碼中轉換成 Bitmap 對象,如下:
Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap);
在獲取的同時,我們還可以對圖像進行任意比例的縮放:
Bitmap originalBitmap = getBitmap();
Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, false);
反過來,我們也可以將 Bitmap 轉換成一個 Drawable 對象:
Drawable drawable = new BitmapDrawable(getResources(),bitmap);
4. 通過 xml 聲明 Drawable
我們可以在 xml 中聲明很多種類型的 Drawable,用于對各種動畫、背景、狀態等等進行描述。
4.1 Shape Drawables
Shape Drawables 可以用來定義一個 View 的外形、顏色、漸變等等屬性,它的最大的有點就是可以根據任意尺寸的 View
進行自適應,代碼示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="10dp"
android:color="#FFFFFFFF" />
<gradient
android:endColor="#EF3434AB"
android:startColor="#FF98df9d"
android:angle="45" />
<corners
android:bottomRightRadius="10dp"
android:bottomLeftRadius="10dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
</shape>
以上代碼分別為背景設置了邊框、漸變、角弧度,編寫完直接作為背景資源設置即可:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/myshape"
android:orientation="vertical" >
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</EditText>
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RadioButton
android:id="@+id/radio0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/celsius" >
</RadioButton>
<RadioButton
android:id="@+id/radio1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fahrenheit" >
</RadioButton>
</RadioGroup>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/calc"
android:onClick="myClickHandler">
</Button>
</LinearLayout>
4.2 State Drawables
State Drawables 用來描述一個 View 在不同狀態下的形態,我們可以給每一種狀態設置一中背景樣式,比如我們可以讓我們的 Button 在點擊、選擇和默認態下呈現不同的樣式:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_pressed"
android:state_pressed="true" />
<item android:drawable="@drawable/button_checked"
android:state_checked="true" />
<item android:drawable="@drawable/button_default" />
</selector>
4.3 Animation Drawables
Animation Drawables 是一種動畫資源,我們可以將動畫的時長、形態、起終點等信息描述在 xml 中,如下:
<animation-list android:id="@+id/selected" android:oneshot="false">
<item android:drawable="@drawable/phase1" android:duration="100" />
<item android:drawable="@drawable/phase2" android:duration="200" />
<item android:drawable="@drawable/phase3" android:duration="300" />
</animation-list>
同樣在 Java 代碼中直接作為背景設置:
ImageView image = (ImageView)findViewById(R.id.img);
img.setBackgroundResource(R.drawable.animation);
AnimationDrawable frameAnimation = (AnimationDrawable) image.getBackground();
frameAnimation.start();
4.4 自定義 Drawable
除了上面常用的系統提供的 Drawable 之外,我們還可以自定義自己想要的圖片資源,在本節的示例中我們就來自定義一個資源樣式。
5. Drawable 使用示例
我們通常使用的 ImageView 都是矩形的,但是為了讓 UI 樣式更
5.1 Drawable 實現
既然要自定義 Drawable 資源,那么首先需要創建一個類繼承自 Drawable,然后在構造器中創建畫筆“Paint”,然后在draw()
方法中繪制圖案即可,代碼示例如下:
package com.emercy.myapplication;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
public class RoundCornerDrawable extends Drawable {
private Paint mPaint;
private Bitmap mBitmap;
public RoundCornerDrawable(Bitmap bitmap) {
this.mBitmap = bitmap;
BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(bitmapShader);
}
@Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight()), 100, 100, mPaint);
}
@Override
public void setAlpha(int i) {
mPaint.setAlpha(i);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
// 返回drawable實際寬高
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
}
}
我們在構造器中創建了一個畫筆,并傳入了 Bitmap 對象,此后系統在繪制的時候回調draw()
方法,完成圓角形狀的繪制,這樣就完成了一個圓角 bitmap 的裁剪工作。
5.2 MainActivity 主邏輯
在主邏輯中我們直接拿到 ImageView,然后獲取我們要設置的 Bitmap 資源,直接通過setBackground()
方法設置給 ImageView,這樣呈現出來的圖片就是圓角形狀。
package com.emercy.myapplication;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import java.io.InputStream;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView image = (ImageView) findViewById(R.id.image);
InputStream resource = getResources().openRawResource(R.raw.avatar);
Bitmap bitmap = BitmapFactory.decodeStream(resource);
image.setBackground(new RoundCornerDrawable(bitmap));
}
}
編譯后效果如下,展示一張圓角圖片:
6. 小結
本節學習了一個很多人經常用到卻很少留意的類,在給 View 設置背景、前景等圖片及樣式的時候都離不開 Drawable 的參與。首先需要學習系統提供的一些常用 Drawable 對象,這樣其實在大多數場景都能應對,如果要處理一些特殊的樣式可以采用自定義 Drawable 的方式。