1. 程式人生 > >Andriod中繪(畫)圖----Canvas的使用詳解

Andriod中繪(畫)圖----Canvas的使用詳解

            由於在網路上找到關於Canvas的使用都比較抽象,也許是我的邏輯思維不太好吧,總是感覺理解起來比較困難,

    尤其是save()和restore()方法的使用。本篇文章的內容就是對Canvas的使用進行一下總結,包括它的兩種不同的使用

    情節和它的一些方法進行一下說明。

       1  Bitmap,可以來自資源/檔案,也可以在程式中建立,實際上的功能相當於圖片的儲存空間;

   2  Canvas,緊密與Bitmap聯絡,把Bitmap比喻內容的話,那麼Canvas就是提供了眾多方法操作Bitamp的平臺;

Paint,與Canvas緊密聯絡,是"畫板"上的筆刷工具,也用於設定View控制元件上的樣式;

Drawable,如果說前三者是看不見地在記憶體中畫圖(虛擬的),那麼Drawable就是把前三者繪圖結果表現出來的介面(真實的)。

              Drawable多個子類,例如:點陣圖(BitmapDrawable)、圖形(ShapeDrawable)、圖層(LayerDrawable)等。

    我們打個簡單的比方吧:

                Paint        就是畫筆

                Bitmap    就是畫布

                Canvas   就是畫家

     於是,畫家可以通過畫筆可以在畫布上進行任何的畫畫。

Canvas的兩種使用情形,從Canvas物件的獲得角度分析:

    1、  自定義View和自定義SurfaceView中獲得Canvas物件

       由於自定義View和SurfaceView在顯示介面中已經獲得了顯示區域,canvas物件只不過是在其顯示(繪畫)區域進行介面佈局

  的設計,當操作完畢後,系統會顯示canvas的操作結果。

       自定義View的繪圖方法為:

//存在canvas物件,即存在預設的顯示區域
	@Override
	public void draw(Canvas canvas) {
         //canvas繪圖
        }


      SurfaceView的繪圖方法為,例如:

           SurfaceView  surfaceView = new MySurfaceView() ;         //建立一個Surface物件
           SurfaceHolder surfaceHolder = surfaceView. getHolder() ;  //獲得SurfaceHolder物件
           Canvas   canvas  = surfaceHolder.lockCanvas() ;          //獲得canvas物件
           //進行繪圖操作
           surfaceHolder.unlockCanvasAndPost(canvas) ;            //釋放canvas鎖,並且顯示檢視

    2、  在其他情形下,我們需要通過程式碼建立一個Canvas物件,並且在繪畫成功後,將該畫圖區域轉換為Drawable圖片

  或者通過setBitmap(bitmap)顯現出來。一般步驟為:

   //建立一個的Bitmap物件 

      Bitmap bitmap = Bitmap.createBitmap(200, 100, Config.ARGB_8888) ;
     //建立一個canvas物件,並且開始繪圖
      Canvas canvas = new Canvas (bitmap) ;

     ImageView imgView  = new ImageView(this) ;  //或者其他可以設定背景圖片的View控制元件
    

      //為ImageView設定影象
      //將Bitmap物件轉換為Drawable影象資
      Drawable drawable = new BitmapDrawable(bitmap) ;
     imgView .setBackgroundDrawable(drawable) ;

 
     或者簡單點:  imgView  .setImageBitmap(bitmap);   


     這兩種方式都可以顯示我們的繪圖。

 Canvas方法分析:

         clipXXX()方法族

           說明:在當前的畫圖區域裁剪(clip)出一個新的畫圖區域,這個畫圖區域就是canvas物件的當前畫圖區域了。

              例如:clipRect(new Rect()),那麼該矩形區域就是canvas的當前畫圖區域了。

public int save()

           說明:儲存已經由canvas繪畫出來的東西,在save()和restore()方法之間的操作不對它們造成影響,例如旋轉(roate)等。

               而且對canvas的操作(roate和translate)都是臨時的,restore()後不再存在。

  public voidrestore()

           說明:復原sava()方法之前儲存的東西資源。

 drawXXX()方法族

           說明:以一定的座標值在當前畫圖區域畫圖。

           注意:圖層會疊加,即後面繪畫的圖層會覆蓋前面繪畫的圖層。

 需要注意的方法是:

   public voiddrawRect(float left, float top, float right, float bottom,Paint paint)

           說明:繪製一個矩型。需要注明的是繪製矩形的引數和Java中的方法不一樣。

該方法的引數圖解說明如下:

        各位看官請注意:圖中X、Y軸方向標記錯誤。 自己也懶得重新修正了。

          

           那麼,矩形的高 height = bottom  - right 

                      矩形的寬 width  = right – left

       PS :假如drawRect的引數有誤,比如right < left ,Android是不會給我們檢查的,也不會提示相應的錯誤資訊,

           但它會繪畫出一個高或寬很小的矩形,可能不是你希望的。

      public voidtranslate(float dx, float dy)

          說明:在當前的座標上平移(x,y)個畫素單位

                    若dx <0 ,沿x軸向上平移; dx >0  沿x軸向下平移

                    若dy <0 ,沿y軸向上平移; dy >0  沿y軸向下平移

public void rotate(float degrees)

說明:旋轉一定的角度繪製圖像。

         PS :從截圖上看,影象是確實旋轉了,但是我找不到旋轉的依據中心。

下面給出該Demo的截圖,可以更改一些引數後自己觀察效果。

  1、佈局檔案 main.xkl :  採用了兩個ImageView來顯示bitmap繪圖物件, 讓後採用了一個自定義View繪圖

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">

	<View android:layout_width="fill_parent" android:layout_height="2dip" android:background="#800080" android:layout_marginTop="2dip"></View>
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="顯示canvas區域以及clip方法的使用" />

	<ImageView android:id="@+id/imgClip" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:layout_marginTop="10dip" />

	<View android:layout_width="fill_parent" android:layout_height="2dip" android:background="#800080" android:layout_marginTop="2dip"></View>
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="save方法和restore方法的使用" />
   	<ImageView android:id="@+id/imgSave" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:layout_marginTop="10dip" />

	<View android:layout_width="fill_parent" android:layout_height="2dip" android:background="#800080" android:layout_marginTop="2dip"></View>
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="自定義View,獲得了一個Canvas物件和繪圖區域" />
	<com.qin.canvas.MyView android:id="@+id/myView"
		android:layout_width="fill_parent" android:layout_height="200px" />

</LinearLayout>


    2、自定義View  , MyView.java,

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.Bitmap.Config;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View{

	private Paint paint  = new Paint() ;
	
	public MyView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	public MyView(Context context , AttributeSet attrs){
		super(context,attrs);
	}
	//存在canvas物件,即存在預設的顯示區域
	@Override
	public void draw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.draw(canvas);
		//加粗
		paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
		paint.setColor(Color.BLUE);
		canvas.drawText("自定義View,canvas物件已經存在。", 30, 40, paint);
		canvas.drawRect(10, 10, 30, 30, paint);
		
		//將icon影象轉換為Bitmap物件
      	Bitmap iconbit = BitmapFactory.decodeResource(getResources(), R.drawable.icon) ;
      	canvas.drawBitmap(iconbit, 40,40, paint);
	}
}


  3、主工程檔案 MainActivity.java

public class MainActivity extends Activity {
	//畫筆物件 paint
	private Paint paint = new Paint() ;   //記得要為paint設定顏色,否則 看不到效果
	private ImageView imgClip ;  // 繪圖區域以及clip方法
	private ImageView imgSave ;  // save方法以及restore
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
          setContentView(R.layout.main) ;
          
          imgClip = (ImageView)findViewById(R.id.imgClip) ;
          imgSave = (ImageView)findViewById(R.id.imgSave);
          
          clip_drawCanvas() ; // 繪圖區域以及clip方法
          save_drawCanvas();  // save方法以及restore
    }
    //這樣的情況下,需要建立Canvas物件,然後在此物件上進行操作
    //對bitmap操作完成後,,顯示該Bitmap有以下兩種操作。
    //1、需要將bitmap轉換為Drawable物件  Drawable drawable = new BitmapDrawable(bitmap) ;
    //2、直接setImageBitmap(bitmap)
    private void  clip_drawCanvas(){
      	//將icon影象轉換為Bitmap物件
      	Bitmap iconbit = BitmapFactory.decodeResource(getResources(), R.drawable.icon) ;
        
      	//建立一個的Bitmap物件
      	Bitmap bitmap = Bitmap.createBitmap(200, 150, Config.ARGB_8888)  ;
      	
      	Canvas canvas = new Canvas (bitmap) ;
      	//設定顏色來顯示畫圖區域
      	canvas.drawColor(Color.RED);

      	paint.setColor(Color.BLACK);
      	canvas.drawText("原先的畫圖區域--紅色部分", 60,50,paint) ;
      	//畫bitmap物件
      	canvas.drawBitmap(iconbit, 20, 20, paint);
      	
      	//剪裁一個區域,當前的操作物件為Rect裁剪的區域
      	Rect rect = new Rect (10,80,180,120) ;
      	
      	//當前的畫圖區域為Rect裁剪的區域,而不是我們之前賦值的bitmap
      	canvas.clipRect(rect)  ;
      	canvas.drawColor(Color.YELLOW);
        //設定顏色來顯示畫圖區域
      	paint.setColor(Color.BLACK);
    	canvas.drawText("裁剪clip後畫圖區域-黃色部分", 10,100,paint) ;
    	
    	//將Bitmap物件轉換為Drawable影象資源
      	//Drawable drawable = new BitmapDrawable(bitmap) ;
      	//img.setBackgroundDrawable(drawable) ;
    	
    	//顯示,同上
      	imgClip.setImageBitmap(bitmap);
    }
    
    private void save_drawCanvas(){
     	//將icon影象轉換為Bitmap物件
      	Bitmap iconbit = BitmapFactory.decodeResource(getResources(), R.drawable.icon) ;
      	
    	//建立一個的Bitmap物件
      	Bitmap bitmap = Bitmap.createBitmap(200, 100, Config.ARGB_8888)  ;
   
    	Canvas canvas = new Canvas (bitmap) ;

    	paint.setColor(Color.GREEN);
    	paint.setTextSize(16);  //設定字型大小
    	canvas.drawRect(10, 10, 50, 8, paint);
    	canvas.drawText("我沒有旋轉",50, 10, paint);
    	//儲存canvas之前的操作,在sava()和restore之間的操作不會對canvas之前的操作進行影響
    	canvas.save() ;
    	
    	//順時針旋轉30度
    	canvas.rotate(30) ;
    	canvas.drawColor(Color.RED);
    	canvas.drawBitmap(iconbit, 20, 20, paint);
    	canvas.drawRect(50, 10, 80, 50, paint);
        //canvas.translate(20,20);
    	canvas.drawText("我是旋轉的",115,20, paint);
    	
    	//復原之前save()之前的屬性,並且將save()方法之後的roate(),translate()以及clipXXX()方法的操作清空
    	canvas.restore();
    	
    	//平移(20,20)個畫素
    	//canvas.translate(20,20);
    	canvas.drawRect(80, 10, 110,30, paint);
    	canvas.drawText("我沒有旋轉",115,20, paint);

    	//將Bitmap物件轉換為Drawable影象資
    	//為ImageView設定影象
    	//imgSave.setImageBitmap(bitmap);
    	
    	Drawable drawable = new BitmapDrawable(bitmap) ;
    	imgSave.setBackgroundDrawable(drawable) ;
    	
    }
}


          總的來說,Canvas理解起來還是比較糾結的,尤其是它的幾個方法真是讓人頭疼, 希望你能夠自己編寫相應的程式碼

  理解透徹,才真正的有所收穫。

相關推薦

Andriod()----Canvas的使用

            由於在網路上找到關於Canvas的使用都比較抽象,也許是我的邏輯思維不太好吧,總是感覺理解起來比較困難,     尤其是對save()和restore()方法的使用。本篇文章的內容就是對Canvas的使用進行一下總結,包括它的兩種不同的使用

eclipsesvn(轉)

tin note 引用 pda call use ips linked Opens - 已忽略版本控制的文件。可以通過Window → Preferences → Team → Ignored Resources.來忽略文件。A file ignored by versio

UML---用例的Include和Extend

前言:   在做UML相關題的時候,發現總是分不清Include和Extend之間的區別,特此釋出一篇部落格,來總結一下這兩個關係的不同,同時也分享給大家,讓了此篇部落格的同學們都不會再迷糊 Include: Include是指“包含的關係”,指多個用例中都包含一個

PlantUML、流程圖、時序使用

程式設計師難免要經常畫流程圖,狀態圖,時序圖等。以前經常用 visio 畫,經常為矩形畫多大,擺放在哪等問題費腦筋。有時候修改文字後,為了較好的顯示效果不得不再去修改圖形。今天介紹的工具是如何使用 PlantUML 的外掛畫流程圖,狀態圖,時序圖等。這是一種程式設計師看了就會愛上

html5 canvas的屬性和方法

建立一個Canvas畫布的方法如下 <canvas id=”canvas” width=”600” height=”400”></canvas> 可以在標籤中新增<canvas>標籤不可用時的替代文字,如下所示: <canv

android canvas layer (層)與進階

1 概述 前面的canvas變換文章中,已經粗略的講解過saveLayer的知識,只是圖層的概念沒有詳細的講解。這裡將詳細講解layer。在使用相關方法和flag的時候,先關閉硬體加速。如果需要開啟,參照谷歌官方的硬體加速表格。硬體加速版本 2 save

Javascript的apply與call

選項 this 模式 div sun fun object 面向 傳遞     JavaScript中有一個call和apply方法,其作用基本相同,但也有略微的區別。  一、方法定義   1、call 方法   語法:call([thisObj[,arg1[, arg2[

JQuery$.ajax()方法參數(轉載)

瀏覽器 object 服務器 字符串 false type: 要求為String類型的參數,請求方式(post或get)默認為get。註意其他http請求方法,例如put和 delete也可以使用,但僅部分瀏覽器支持。timeout: 要求為Number類型的參數,設置請求超時時

JavaScript數組對象

稀疏數組 nsh isa 學習過程 bnf value 明顯 global sci Array對象即數組對象用於在單個變量中存儲多個值,JS的數組是弱類型的,所以允許數組中含有不同類型的元素,數組元素甚至可以是對象或者其他數組。 創建數組的語法 1、Array構造器 1

react native textInput的value屬性

hold eric 工作 als size 保持 chang 無奈 bsp TextInput用法就不多講了,主要記錄下遇到的一個怪問題。 背景:項目需要開發一個充值頁面,需要一個輸入框,然後幾個按鈕,輸入框是允許用戶自己輸入任意金額,按鈕是可以讓用戶快捷選擇金

TP5關聯模型的使用

php 關聯模型 tp5 首先是model裏,舉個例子,user.php<?phpnamespace app\rbac\model;use think\Model;class User extends Model{ public function roleusers() {

Android StudioGit和GitHub使用

可能 必須 窗口 gin 擁有 說明 詳細 對話 發現   一、Git和GitHub簡述    1.Git    分布式版本控制系統,最先使用於Linux社區,是一個開源免費的版本控制系統,功能類似於SVN和CVS。Git與其他版本管理工具最大的區別點和優點就是分布式;  

Django的request對象

當前 perm 請求 詳細 spa ati 用戶輸入 刪除 完整路徑 URLconf文件匹配到用戶輸入的路徑後,會調用對應的view函數,並將 HttpRequest對象 作為第一個參數傳入該函數。 下面說說HttpRequest對象: 他其實是一個實例對象,屬性有:

css偽類/偽元素

input 其他 中文 tro 網頁 單元 web link 語言 一、偽類和偽元素 偽類和偽元素都是用來修飾不在文檔樹中的部分,區別在於, 偽類用於當已有元素處於的某個狀態時,為其添加對應的樣式,這個狀態是根據用戶行為而動態變化的(如:hover/:active)。

Java的異常和處理

stat 一個 局部變量 lose 出了 object sta tof .html 原文出處:代碼鋼琴家 簡介 程序運行時,發生的不被期望的事件,它阻止了程序按照程序員的預期正常執行,這就是異常。異常發生時,是任程序自生自滅,立刻退出終止,還是輸出錯誤給用戶?或者用C語

Swift 的Closures(閉包)

mount light sca ring 需要 line rem sin 代碼 Swift 中的Closures(閉包)詳解 在Swift沒有發布之前,所有人使用OC語言編寫Cocoa上的程序,而其中經常被人們討論的其中之一 -- Block 一直備受大家的喜愛。在Swif

Spring的applicationContext文件

finance 初始化 tgui 解析 示例 row -m 所有 table <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/sche

JQuery$.ajax()方法參數

返回 自動轉換 time err last 需要 可選 修改 方式 url: 要求為String類型的參數,(默認為當前頁地址)發送請求的地址。 type: 要求為String類型的參數,請求方式(post或get)默認為get。註意其他http請求方法,例如put和

C#的IDisposable模式用法

數據庫 nor 是否 entry block 記錄日誌 自定義 技術分享 ssa 本文實例講述了C#中IDisposable模式的用法,針對垃圾資源的回收進行了較為詳細的講解。分享給大家供大家參考之用。具體方法如下: 首先,對於垃圾回收而言,在C#中,托管資源的垃圾回收是

vue2.0 #$emit,$on的使用

額外 return turn isp div 傳遞 call sele 發的 vue1.0中 vm.$dispatch 和 vm.$broadcast 被棄用,改用$emit,$on 1. vm.$on( event, callback ) 監聽當前實例上的自定義事件。