經常要和繪圖打交道,總是用Canvas,bitmap,Paint,但是對它們的理解總是模糊,這裏作下總結,加深對繪圖的理解。
查詢Canvas的官方解釋:Canvas用來實現對繪圖的操作。你需要4個組件來實現繪圖的操作:
a).bitmap,保存着像素
b).canvas.執行畫圖的命令(向bitmap執行寫操作)
c).drawing primtive(e.g.Rect,Path,text,bitmap).繪圖的原始內容。
d).paint.(用來描述繪圖時的使用的顏色和風格)
這些解釋都很抽象,下面我來說下對它們的形象的理解,說明這4個基本控件,這樣加深印象:
我們就用現實中的畫圖來比擬對android中繪圖的理解:
a)bitmap.我們繪圖肯定需要一塊畫布,這個畫布承載內容用來表現所要顯示的圖。它有大小,你可以在上面塗顏料進行繪圖,或什麼都不塗。
b).canvas.畫布本身不會被繪製,只有當畫家去操作畫筆,畫布纔會繪製上圖畫。這裏的canvas就像相當於畫家執行畫圖的操作,繪圖的過程。
c).drawing primitive.畫家繪圖需要參照物,比如你繪圖,肯定是有個目標,比如繪製一個字體,一個圓圈,一個矩形(Rect),另一幅圖(bitmap)。
d).paint.繪圖需要畫筆,paint就相當於這個畫筆,你可以定製顏色,粗細。
下面瞭解Canvas,bitmap,paint一些常用的方法:
Bitmap
.獲取bitmap方法
讀取InputStream得到位圖
InputStream is = getResources().openRawResource(R.drawable.ic_launcher);
BitmapDrawable bd = new BitmapDrawable(is);
Bitmap bp = bd.getBitmap();
解碼位圖來獲取位圖,如果你在解析大圖片遇到OOM問題,不妨嘗試這個方法,這個方法利用JNI調用來解析bitmap,減輕了java層空間的壓力。Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
位圖的創建,你可以利用下面方法來創建一個bitmapmatrix 指定對bitmap像素的操作
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter);
//width,height用來指定創建圖片的大小,config用來指定創建圖片的質量,
其中config有共有4個標準: ALPHA_8,ARGB_4444,ARGB_8888,RBG_565,這些標準分別定義圖片像素存儲的情況,RBG_565是比較常用的,
ARBG_8888指定的圖片質量最高
createBitmap(int width, int height, Bitmap.Config config);
createBitmap(Bitmap source, int x, int y, int width, int height);
Canvas
Canvas();創建一個空畫布,它必須綁定bitmap纔有效,一般以bitmap來創建一個bitmap的操作,當canvas進行繪圖,他繪製的內容都繪在bitmap上。
常見的Canvas繪製使用場合:
a.自定義View時繪製
@Override
OnDraw(Canvas canvas){
//利用canvas執行繪圖操作
}
b.利用surfaceView時繪製
SurfaceHoler holder = SurfaceView.getHolder();
Canvas canvas = holder.lockCanvas();
//利用canvas進行繪圖操作
holder.unlockCanvasAndPost(canvas);//對canvas解鎖,並更新
繪製圖形的方法:
drawCircle(float cx, float cy, float radius, Paint paint);//繪製圓圈
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)//繪製直線
裁剪繪圖區域
clipXXX()方法類
從當前區域裏裁剪一塊新的畫圖區域,裁剪後的新區域即爲繪圖的新區域。
save(),restore()方法
在繪圖時,我們經常會用到canvas類的save(), restore()方法,它們到底是怎麼用的呢?
這裏有篇詳細講解這兩個方法的文章,和大家分享:
https://developer.mozilla.org/en/Canvas_tutorial/Transformations
*save,用來保存Canvas狀態,調用之後,你可以調用canvas對畫布進行平移、縮放、裁剪等操作。
*restore.用來恢復Canvas之前保存的狀態,這樣不僅能夠複用先前保存的狀態,節約資源,另一方面避免對影響圖片後續的繪製。
Paint
Paint(),//創建畫筆
setColor(int color)//設置畫筆的顏色
setAlpha(int a)//設置圖片透明度
setDither(boolean dither)//設置畫筆是否反鋸齒
setStrokeWidth(float width)//設置畫筆的寬度
小例子學習
做一小例子溫習鞏固繪圖的操作,要求實現仿捲簾拉起效果。
先簡述一下情景:。首先,手機上顯示一張完整的圖片,圖片頂端固定不變。然後,手指在圖片上開始滑動,圖片的底部隨着手指位置而不斷變化。你看到的效果是圖片的從頂端顯示你手指滑動的所在位置。所以,你看到的總是不完整的圖片。先上效果,這樣大家更好理解。
爲了實現上述效果的複用,我們可以自定義一個view,可以設置背景圖片,提示的箭頭的圖片以及圖片頂端保留空間大小。
1.自定義MovingView.java,實現上述功能
package com.lawrence;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MovingView extends View {
private Bitmap backgroundBitmap;
private Bitmap handleBitmap;
private Bitmap showBitmap;
private int backgroundWidth;
private int backgroundHeight;
private int handleWidth;
private int handleHeight;
private int currentY;
private int showHeight;
private int topSpace;
private Canvas mCanvas;
private Rect backgroundSrc;
public MovingView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Movingview);
//獲取背景圖片
Drawable backgroundDrawable = a.getDrawable(R.styleable.Movingview_movingbackground);
//獲取拉手圖片
Drawable handleDrawable = a.getDrawable(R.styleable.Movingview_handlebackground);
//獲取頂端保留的高度大小。這個高度用做滑動到頂部保留的最小高度。
topSpace = (int) a.getDimension(R.styleable.Movingview_extraspace, 10);
backgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
handleBitmap = ((BitmapDrawable) handleDrawable).getBitmap();
//獲取圖片高寬
backgroundWidth = backgroundBitmap.getWidth();
backgroundHeight = backgroundBitmap.getHeight();
handleWidth = handleBitmap.getWidth();
handleHeight = handleBitmap.getHeight();
//根據圖片大小創建一個相同大小的bitmap
showBitmap = Bitmap.createBitmap(backgroundWidth, backgroundHeight + (handleHeight >> 1), Config.RGB_565);
//創建一個canvas,並綁定bitmap。
mCanvas = new Canvas(showBitmap);
//繪製定backgroundBitmap到showBitmap。
mCanvas.drawBitmap(backgroundBitmap, 0, 0, null);
//在backgroundBitmap底部的中間位置繪製拉手圖片
mCanvas.drawBitmap(handleBitmap, (backgroundWidth - handleWidth) >> 1, backgroundHeight - (handleHeight >> 1), null);
}
public MovingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MovingView(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//設置圖片的大小爲此View的大小
setMeasuredDimension(backgroundWidth, backgroundHeight + (handleHeight >> 1));
}
@Override
protected void onDraw(Canvas canvas) {
//更新繪製圖片
canvas.drawBitmap(showBitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
currentY = (int) event.getY();
showHeight = currentY;
if(showHeight > backgroundHeight)
showHeight = backgroundHeight;
if(showHeight < topSpace)
showHeight = topSpace;
//清除圖片
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
//根據滑動位置確定新繪製區域
backgroundSrc = new Rect(0, 0, backgroundWidth, showHeight);
//繪製背景
mCanvas.drawBitmap(backgroundBitmap, backgroundSrc, backgroundSrc, null);
//繪製拉手
mCanvas.drawBitmap(handleBitmap, (backgroundWidth - handleWidth) >> 1, showHeight - (handleHeight >> 1), null);
invalidate();//更新
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}
2.自定義MovingView的屬性: <?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Movingview">
<attr name="movingbackground" format="reference"/>
<attr name="handlebackground" format="reference"/>
<attr name="extraspace" format="dimension"/>
</declare-styleable>
</resources>
3.佈局文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:moving="http://schemas.android.com/apk/res/com.lawrence"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<com.lawrence.MovingView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
moving:extraspace="30dp"
moving:movingbackground="@drawable/bofucur"
moving:handlebackground="@drawable/updownsel"
/>
</LinearLayout>
主Activity就不貼了,很簡單,只要setcontentView(R.layout.main).
附:Demo源碼位置:http://download.csdn.net/detail/a2758963/4459566