android之繪圖——Canvas,bitmap,Paint的理解

     經常要和繪圖打交道,總是用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);
          位圖的創建,你可以利用下面方法來創建一個bitmap
matrix 指定對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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章