Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 2D繪圖(Canvas+paint)詳解

Android 2D繪圖(Canvas+paint)詳解

編輯:關於Android編程

目錄:
1.重要類概述
2.重要類的常用方法
2.簡單View繪制(圓、圓弧、矩形、弧形、圓角矩形、橢圓、文字等)
3.setXfermode(Xfermode xfermode)的運用

1.重要類概述
在2D繪制中我們常用的類,也是兩個最重要的類就是Canvas(畫布)和Paint(畫筆),通過Canvas我們可以設置
繪制的形狀和路徑,當然僅僅形狀和路徑是不行的,我們還需要顏色啊,陰影啊,透明度等等的設置,這時候就是Paint的
事情了,Paint的作用主要就是設置繪圖的風格,下面我們就總結一下這兩個類常用的方法。

2.重要類的常用方法
(1)Canvas:

構造類方法:
Canvas()        //構造方法
Canvas(Bitmap bitmap) //帶參構造方法,創建一個以bitmap位圖為背景的Canvas

裁切類方法:
		clipPath(Path path, Region.Op op) //根據特殊path組合裁切圖像,Region.Op定義了Region支持的區域間運算種類。
		
		clipRect(Rect rect, Region.Op op) //根據矩形組合裁切圖像
		
		clipRegion(Region region, Region.Op op)
		
		concat(Matrix matrix) //通過matrix的設置可以對繪制的圖形進行繪制伸縮和位移

圖形繪制類方法:
		drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) //繪制弧形
		
		drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) //繪制bitmap位圖
		
		drawPicture(Picture picture, RectF dst) //繪制圖片
		
		drawCircle(float cx, float cy, float radius, Paint paint) //繪制圓
		
		drawLine(float startX, float startY, float stopX, float stopY, Paint paint) //繪制線
		
		drawLines(float[] pts, int offset, int count, Paint paint) //可以選擇性的去掉一些數據繪制多條線
		
		drawOval(RectF oval, Paint paint) //繪制橢圓
		
		drawPath(Path path, Paint paint) //繪制路徑
		
		drawPoint(float x, float y, Paint paint) //繪制點
		
		drawPoints(float[] pts, int offset, int count, Paint paint) //繪制多個點
		
		drawPosText(String text, float[] pos, Paint paint) //繪制文本,float[] pos指定每個文本位置
		
		drawRect(float left, float top, float right, float bottom, Paint paint) //繪制矩形
		
		drawRoundRect(RectF rect, float rx, float ry, Paint paint) //繪制圓角矩形
		
		drawText(String text, float x, float y, Paint paint) //繪制string文本
		
		drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint) //路徑上繪制文本

填充類方法:
		drawRGB(int r, int g, int b) //使用RGB指定顏色填充canvas的bitmap畫布
		
		drawARGB(int a, int r, int g, int b) //使用ARGB指定顏色填充canvas的bitmap畫布

其他操作類方法:
		save() //保存Canvas狀態,save之後,可以調用Canvas的平移、放縮、旋轉、錯切、裁剪等操作
		
		restore() //恢復Canvas之前保存的狀態,防止save後對Canvas執行的操作對後續的繪制有影響
		
		rotate(float degrees, float px, float py) //旋轉
		
		scale(float sx, float sy) //縮放
		
		skew(float sx, float sy) //扭曲
		
		translate(float dx, float dy) //平移

(2)Paint:
文本設置相關方法:
			isUnderlineText() //判斷是否有下劃線
			
			setUnderlineText(boolean underlineText) //設置下劃線
			
			getLetterSpacing() //獲取字符間的間距
			
			setLetterSpacing(float letterSpacing) //設置字符間距
			
			getFontSpacing() //獲取行間距
			
			isStrikeThruText() //判斷文本是否有刪除線
			
			setStrikeThruText(boolean strikeThruText) //設置文本刪除線
			
			getTextSize() //獲取字體大小
			
			setTextSize(float textSize) //設置字體大小
			
			getTypeface() //獲取文字字體類型
			
			setTypeface(Typeface typeface) //設置文字字體類型
			
			getTextSkewX() //獲取斜體文字的值
			
			setTextSkewX(float skewX) //設置斜體文字的值,負數為右傾斜,正數為左傾斜 官方推薦-0.25
			
			getTextScaleX() //獲取文字水平縮放值
			
			setTextScaleX(float scaleX) //設置文本水平縮放值
			
			getTextAlign() //獲取文本對其方式
			
			setTextAlign(Paint.Align align) //設置文本對其方式
			
			ascent() //baseline之上至字符最高處的距離
			
			descent() //baseline下面到字符最低處的距離
			
			measureText(CharSequence text, int start, int end) //測繪文本的寬度
			
		        getTextBounds(char[] text, int index, int count, Rect bounds) //獲取文本寬高


			getTextWidths(String text, int start, int end, float[] widths) //精確獲取文本寬度
			
			getTextLocale() //獲取文本語言地理位置
			
			setTextLocale(Locale locale) //設置文本地理位置,也就是設置對應的語言

繪圖設置相關方法:
			//設置畫筆顏色
			setARGB(int a, int r, int g, int b) 
			setAlpha(int a) 
			setColor(int color)
			
			//獲取畫筆顏色
			getAlpha() 
			getColor() 
			
			isAntiAlias() //判斷是否抗鋸齒
			
			setAntiAlias(boolean aa)  //設置抗鋸齒,雖然耗資源耗時間,但是一般會開啟
			
			getStyle() //獲取畫筆樣式
			
			setStyle(Paint.Style style) //設置畫筆樣式,FILL:實心; FILL_OR_STROKE:同時實心和空心; STROKE:空心
			
			setStrokeCap(Cap cap) //設置畫筆樣式, 圓形(Cap.Round),方形(Cap.SQUARE)
			
			getStrokeWidth() //獲取畫筆的粗細大小
			
			setStrokeWidth(float width) //設置畫筆的粗細大小
			
			clearShadowLayer() //清除陰影層
			
			setShadowLayer(float radius, float dx, float dy, int shadowColor) //設置陰影
			
			getXfermode() //獲取圖形繪制的像素融合模式
			
			setXfermode(Xfermode xfermode) //設置圖形繪制的像素融合模式和疊加模式,就是新繪制的像素與Canvas上對應位置已有的像素按照混合規則進行顏色混合
			
			getShader() //獲取圖形的渲染方式
			
			setShader(Shader shader) //設置圖形的渲染方式,分別有線性渲染(LinearGradient) 環形渲染(RadialGradient) 組合渲染(ComposeShader) 掃描漸變渲染/梯度渲染(SweepGradient)

其他方法:
			reset() //清除畫筆復位

2.簡單View繪制(圓、圓弧、矩形、弧形、圓角矩形、橢圓、文字等)
我們通過自定義View的形式來展示我們繪畫的圖形,所以在此之前我們需要搭建一個自定義View的模型
1.添加自定義類繼承View類(待會我們將在onDraw()方法中繪制我們的圖形)
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-11.
 */
public class DrawCircleView extends View {
    Paint paint;
    public DrawCircleView(Context context) {
        super(context);
    }


    public DrawCircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

2.布局xml文件中應用(通過 包名.類名 的形式 (就像下面com.example.drawview.DrawTextView一樣)指定我們定義的類)




    

接下來我們就可以在onDraw()方法中繪制我們的圖形了

(1)圓的繪制
1.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-11.
 */
public class DrawCircleView extends View {
    Paint paint;
    public DrawCircleView(Context context) {
        super(context);
    }


    public DrawCircleView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //初始化畫筆
        paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //設置畫筆要是,圓形/方形/其他
        paint.setStrokeCap(Paint.Cap.BUTT);
        //設置實心圓
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆大小
        paint.setStrokeWidth(2);
        //設置陰影
        paint.setShadowLayer(5,5,5, Color.BLUE);
        //繪制實心圓
        canvas.drawCircle(300,200,100,paint);
        //設置為空心
        paint.setStyle(Paint.Style.STROKE);
        //設置畫筆大小
        paint.setStrokeWidth(3);
        //繪制
        canvas.drawCircle(500,200,100,paint);


    }


}

1.2 效果圖
\

(2)矩形繪制
2.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-15.
 */
public class DrawRectView extends View {
    public DrawRectView(Context context) {
        super(context);
    }


    public DrawRectView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆的樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置畫筆粗細大小
        paint.setStrokeWidth(3);
        //設置畫筆的所畫圖形的樣式
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆的顏色
        paint.setColor(Color.GREEN);
        //繪制矩形 drawRect(left頂點X坐標, left頂點Y坐標, 右底部X坐標, 右底Y坐標, @NonNull Paint paint)
        canvas.drawRect(200,200,400,400,paint);
        //從新設置畫筆所畫圖形樣式
        paint.setStyle(Paint.Style.STROKE);
        //重新設置畫筆大小
        paint.setStrokeWidth(5);
        //繪制
        RectF rect = new RectF(200,420,400,620);
        canvas.drawRect(rect,paint);




    }
}

2.2 效果圖
\
(3)圓角矩形的繪制
3.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-14.
 */
public class DrawRoundRectView extends View {


    public DrawRoundRectView(Context context) {
        super(context);
    }


    public DrawRoundRectView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas){
      super.onDraw(canvas);
        //聲明並初始化
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫出的圖形是實心還是空心
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆粗細
        paint.setStrokeWidth(2);
        //設置畫筆的樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorPrimaryDark));
/*        if (Build.VERSION.SDK_INT>=21){
            //需要在API 21版本及其以後才能使用,和下面效果相同
            canvas.drawRoundRect(100,100,200,200,20,20,paint);
        }*/
        RectF rect = new RectF(200,200,400,400);
        canvas.drawRoundRect(rect,50,50,paint);
        //從新設置畫筆大小
        paint.setStrokeWidth(5);
        //設置畫筆畫出的圖形未空心
        paint.setStyle(Paint.Style.STROKE);
        //繪制矩形
        // RectF(left頂點x坐標, left頂點Y坐標, right邊底部x坐標, right邊底部Y坐標)
        RectF rect2 = new RectF(200,420,400,620);
        //繪制圓角矩形
        //drawRoundRect(@NonNull RectF rect, x方向上的圓角半徑, Y方向上的圓角半徑, @NonNull Paint paint)
        canvas.drawRoundRect(rect2,50,50,paint);


    }
}

3.2 效果圖
\

(4)橢圓的繪制
4.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawOvalView extends View {
    public DrawOvalView(Context context) {
        super(context);
    }


    public DrawOvalView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆筆尖樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置所畫圖形的填充樣式
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //實例化一個包裹橢圓的矩形,如果為正方形,則橢圓為圓
        RectF rectF = new RectF(200,200,500,400);
        //設置畫布顏色,方便與paint.setColor()對比,看看他們的區別
        canvas.drawColor(Color.BLACK);
        //繪制橢圓
        canvas.drawOval(rectF,paint);
        //設置畫筆的大小
        paint.setStrokeWidth(5);
        //設置繪畫圖形為空心
        paint.setStyle(Paint.Style.STROKE);
        //繪制
        if (Build.VERSION.SDK_INT>=21){
            //API 21以上才能用,與上面的繪畫方式效果一致
            canvas.drawOval(200,450,500,650,paint);
        }
    }
}

4.2 效果圖
\
(5)點的繪制
5.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawPointView extends View {
    public DrawPointView(Context context) {
        super(context);
    }


    public DrawPointView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        //設置畫筆大小,我這邊設置的大點,方便觀察
        paint.setStrokeWidth(50);
        //設置畫筆筆尖樣式,默認為Paint.Cap.SQUARE,待會切換一下,你就會知道它的作用了
        // 網上有說在設置paint.setStrokeCap(Paint.Cap.ROUND|SQUARE);之前需要同時設置
        //paint.setStrokeJoin(Paint.Join.ROUND|MITER);我測試了好像不需要也能達到切換的目的
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setColor(getResources().getColor(R.color.colorAccent));
        canvas.drawPoint(200,200,paint);


        paint.setStrokeCap(Paint.Cap.BUTT);
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawPoint(300,200,paint);


        paint.setStrokeCap(Paint.Cap.SQUARE);
        paint.setColor(getResources().getColor(R.color.colorAccent));
        canvas.drawPoint(400,200,paint);


        paint.setStrokeCap(Paint.Cap.BUTT);
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawPoint(500,200,paint);


        //設置畫筆樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //繪制多個點
        canvas.drawPoints(new float[]{150,300,250,300,350,300,450,300,550,300},paint);


    }
}

5.2 效果圖
\
(6)線段的繪制
6.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawLineView extends View {
    public DrawLineView(Context context) {
        super(context);
    }


    public DrawLineView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置畫筆顏色
        paint.setColor(Color.RED);
        //設置畫筆大小
        paint.setStrokeWidth(20);
        //畫線段,參數分別是線段起始點的坐標和終點的坐標,和預設的畫筆
        canvas.drawLine(100,200,600,200,paint);
        //LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
        //TileMode tile),(x0,y0) (x1,y1)源碼上說是梯度的坐標,不是很懂,我個人理解為後面設置的每一種顏色渲染的長度,坐標間隔越小,渲染的顏色長度越短
        //int colors[]:指示需要渲染的顏色數組  float positions[]:可為null,為null時顏色均勻分布
        //TileMode tile:指示平鋪模式,分別有REPEAT(重復) CLAMP(像素擴散) MIRROR(鏡面投影)
        Shader mShader=new LinearGradient(0,0,100,100,
                new int[]{Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW},
                null,Shader.TileMode.REPEAT);
        //設置畫筆渲染漸變
        paint.setShader(mShader);
        //繪制漸變線段
        canvas.drawLine(100,300,600,300,paint);


    }
}

6.2 效果圖
\
(7)路徑的繪制
7.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawPathView extends View {
    public DrawPathView(Context context) {
        super(context);
    }


    public DrawPathView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆筆尖樣式
        paint.setStrokeCap(Paint.Cap.ROUND);
        //設置填充模式,默認為FILL
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆大小
        paint.setStrokeWidth(3);
        //設置顏色
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        /*Path類的幾個...To()方法:
        *   path.moveTo(x,y)移動到某個點
        *   path.lineTo(x,y)從起始點,默認(0,0)點繪制直線到(x,y)點
        *   path.arcTo()用來繪制弧形
        *   path.cubicTo()用來繪制貝塞爾曲線
        *   path.quadTo()也是繪制貝塞爾曲線的
        * */
        //實例化路徑類
        Path path = new Path();
        //設置移動,不繪制
        path.moveTo(200, 200);
        //從(200,200)畫到(200,400)
        path.lineTo(200, 400);
        //從(200,400)畫到(400,400)
        path.lineTo(400, 400);
        //封閉曲線
        path.close();
        //繪制路徑
        canvas.drawPath(path, paint);
        //設置顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //設置移動,不繪制
        Path path1 = new Path();
        path1.moveTo(200, 200);
        //從(200,200)畫到(200,400)
        path1.lineTo(400, 200);
        //從(200,400)畫到(400,400)
        path1.lineTo(400, 400);
        //封閉曲線
        path1.close();
        //繪制
        canvas.drawPath(path1, paint);
        //初始化路徑
        Path path2 = new Path();
        //設置矩形
        RectF rectF = new RectF(420, 200, 620, 500);
        //取矩形包裹橢圓0°到270°的弧
        path2.arcTo(rectF, 0, 270);
        //封閉弧形
        path2.close();
        //設置填充實心
        paint.setStyle(Paint.Style.FILL);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //繪制圖形
        canvas.drawPath(path2, paint);
        /*
        *quadTo()繪制貝塞爾曲線
         */
        Path path3 = new Path();
        //移動到(200,620)點
        path3.moveTo(200, 620);
        //繪制貝塞爾曲線
        path3.quadTo(300, 420, 400, 620);
        //設置空心
        paint.setStyle(Paint.Style.STROKE);
        //繪制曲線
        canvas.drawPath(path3, paint);
        /*
        * cubicTo()繪制貝塞爾曲線
        * */
        Path path4 = new Path();
        //移動到(300,100)點
        path4.moveTo(300, 100);
        //繪制曲線
        path4.cubicTo(300, 100, 5, 300, 300, 500);
        //設置不填充
        paint.setStyle(Paint.Style.STROKE);
        //繪制
        canvas.drawPath(path4, paint);
    }
}

7.2 效果圖
\
(8)路徑文字+簡單文字的繪制
8.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawTextView extends View {
    public DrawTextView(Context context) {
        super(context);
    }


    public DrawTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        //設置畫筆大小
        paint.setStrokeWidth(3);
        //設置字體大小
        paint.setTextSize(30);
        //設置文字樣式
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        String str = "我知道,你要說我很帥,哈啊哈哈哈哈,字不夠長!";
        //全部顯示,起點在(200,100)點
        canvas.drawText(str,50,100,paint);
        //截取4~9的字符串顯示
        canvas.drawText(str,4,10,200,200,paint);
        //實例化路徑
        Path path = new Path();
        //設置圓形狀路徑,Direction指示文字顯示是逆時針向外還是順時針向內 Path.Direction.CW|Path.Direction.CCW
        path.addCircle(400,400,110, Path.Direction.CW);
        //更具路徑繪制文本
        canvas.drawTextOnPath(str,path,0,0,paint);


        Path path1 = new Path();
        if (Build.VERSION.SDK_INT>=21){
            //API 21以上
            path1.addOval(300,600,500,900, Path.Direction.CCW);
        }
        canvas.drawTextOnPath(str,path1,0,0,paint);
    }
}

8.2 效果圖
\
(9)點文字的繪制
9.1 代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-16.
 */
public class DrawPosTextView extends View {
    public DrawPosTextView(Context context) {
        super(context);
    }


    public DrawPosTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Paint paint = new Paint();
        //設置抗鋸齒
        paint.setAntiAlias(true);
        //設置畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //設置畫筆到校
        paint.setStrokeWidth(5);
        //設置字體顏色
        paint.setTextSize(30);
        canvas.drawColor(Color.BLACK);
        canvas.drawPosText("你看我帥嘛?",new float[]{100,200,200,100,300,200,300,400,200,500,100,400},paint);
    }
}	

9.2 效果圖
\

 

3.setXfermode(Xfermode xfermode)的運用

setXfermode()方法主要是設置圖形繪制的像素融合模式和疊加模式,就是新繪制的像素與Canvas上對應位置已有的像素按照混合規則進行顏色混合
以此實現多樣的自定義View。


由於它的混合模式多達18種,下面我只是選取了其中幾種,然後分別對不在Canvas上創建新Layer且不限制使用軟件渲染與在Canvas上建立新
Layer並且個別模式采用軟件渲染模式進行對比,看看他們的區別。如果又需要了解的原理的可以看看下面這篇博客:
http://blog.csdn.net/iispring/article/details/50472485


1)不在Canvas上創建新Layer且不限制使用軟件渲染
(1)代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-17.
 */
public class XfermodeView extends View {
    public XfermodeView(Context context) {
        super(context);
    }


    public XfermodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);






        /*
        * 默認的Xfermode
        * */


        Paint paint = getPaint();
        //設置繪制圓的畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 200, 100, paint);
        //設置繪制圓角矩形的畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上,當然最好是些兼容性好的,我這裡只是為了方便
            canvas.drawRoundRect(200, 200, 300, 350, 10, 10, paint);


        /*
        * PorterDuff.Mode.ADD模式
        * */


        Paint paint1 = getPaint();
        paint1.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 200, 100, paint1);
        //設置像素融合模式
        paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
        paint1.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 200, 600, 350, 10, 10, paint1);
        //取消像素融合模式的設置
        paint1.setXfermode(null);




        /*
        * PorterDuff.Mode.CLEAR模式
        * */
        Paint paint2 = getPaint();
        paint2.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 500, 100, paint2);
        paint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        paint2.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(200, 500, 300, 650, 10, 10, paint2);
        paint2.setXfermode(null);


         /*
        * PorterDuff.Mode.DARKEN模式
        * */
        Paint paint3 = getPaint();
        paint3.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 500, 100, paint3);
        paint3.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        paint3.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 500, 600, 650, 10, 10, paint3);
        paint3.setXfermode(null);
		
        /*
        * PorterDuff.Mode.LIGHTEN模式
        * */
        Paint paint4 = getPaint();
        paint4.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 800, 100, paint4);
        paint4.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
        paint4.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(200, 800, 300, 950, 10, 10, paint4);


         /*
        * PorterDuff.Mode.MULTIPLY模式
        * */
        Paint paint5 = getPaint();
        paint5.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 800, 100, paint5);
        paint5.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        paint5.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 800, 600, 950, 10, 10, paint5);
        paint5.setXfermode(null);


    }


    public Paint getPaint() {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        return paint;
    }
}

(2)效果截圖

\

2)在Canvas上建立新Layer並且個別模式采用軟件渲染模式
(1)代碼
package com.example.drawview;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;


/**
 * Created by elimy on 2016-10-17.
 */
public class XfermodeView extends View {
    public XfermodeView(Context context) {
        super(context);
    }


    public XfermodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);






        /*
        * 默認的Xfermode
        * */


        Paint paint = getPaint();
        //設置繪制圓的畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 200, 100, paint);
        //設置繪制圓角矩形的畫筆顏色
        paint.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上,當然最好是些兼容性好的,我這裡只是為了方便
            canvas.drawRoundRect(200, 200, 300, 350, 10, 10, paint);


        /*
        * PorterDuff.Mode.ADD模式
        * */


        //canvas.saveLayer()在canvas原畫布上見一個透明的layer
        int layerId = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        Paint paint1 = getPaint();
        paint1.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 200, 100, paint1);
        //設置像素融合模式
        paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
        paint1.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 200, 600, 350, 10, 10, paint1);
        //取消像素融合模式的設置
        paint1.setXfermode(null);
        //將新圖層畫到canvas上
        canvas.restoreToCount(layerId);




        /*
        * PorterDuff.Mode.CLEAR模式
        * */
        int layerId2 = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        Paint paint2 = getPaint();
        paint2.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 500, 100, paint2);
        paint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        paint2.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(200, 500, 300, 650, 10, 10, paint2);
        paint2.setXfermode(null);
        canvas.restoreToCount(layerId2);
         /*
        * PorterDuff.Mode.DARKEN模式
        * */
        int layerId3 = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        Paint paint3 = getPaint();
        paint3.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 500, 100, paint3);
        //禁用掉CPU硬件加速,采用軟件渲染模式,因為DARKEN、LIGHTEN、OVERLAY等幾種混合規則在GPU硬件加速效果展示不出來
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint3.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        paint3.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 500, 600, 650, 10, 10, paint3);
        paint3.setXfermode(null);
        canvas.restoreToCount(layerId3);
        /*
        * PorterDuff.Mode.LIGHTEN模式
        * */
        int layerId4 = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        Paint paint4 = getPaint();
        paint4.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(200, 800, 100, paint4);
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint4.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
        paint4.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(200, 800, 300, 950, 10, 10, paint4);
        paint4.setXfermode(null);
        canvas.restoreToCount(layerId4);
         /*
        * PorterDuff.Mode.MULTIPLY模式
        * */
        int layerId5 = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);
        Paint paint5 = getPaint();
        paint5.setColor(getResources().getColor(R.color.colorPrimary));
        canvas.drawCircle(500, 800, 100, paint5);
        paint5.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        paint5.setColor(getResources().getColor(R.color.colorAccent));
        if (Build.VERSION.SDK_INT >= 21)
            //API 21以上
            canvas.drawRoundRect(500, 800, 600, 950, 10, 10, paint5);
        paint5.setXfermode(null);
        canvas.restoreToCount(layerId5);
    }


    public Paint getPaint() {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        return paint;
    }
}

(2)效果截圖
\
3)PorterDuff.Mode的模式分類
		
        /** [0, 0] */
        CLEAR       (0),
        /** [Sa, Sc] */
        SRC         (1),
        /** [Da, Dc] */
        DST         (2),
        /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
        SRC_OVER    (3),
        /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
        DST_OVER    (4),
        /** [Sa * Da, Sc * Da] */
        SRC_IN      (5),
        /** [Sa * Da, Sa * Dc] */
        DST_IN      (6),
        /** [Sa * (1 - Da), Sc * (1 - Da)] */
        SRC_OUT     (7),
        /** [Da * (1 - Sa), Dc * (1 - Sa)] */
        DST_OUT     (8),
        /** [Da, Sc * Da + (1 - Sa) * Dc] */
        SRC_ATOP    (9),
        /** [Sa, Sa * Dc + Sc * (1 - Da)] */
        DST_ATOP    (10),
        /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
        XOR         (11),
        /** [Sa + Da - Sa*Da,
             Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
        DARKEN      (12),
        /** [Sa + Da - Sa*Da,
             Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
        LIGHTEN     (13),
        /** [Sa * Da, Sc * Dc] */
        MULTIPLY    (14),
        /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
        SCREEN      (15),
        /** Saturate(S + D) */
        ADD         (16),
        OVERLAY     (17);

上面這段代碼來之源碼,看了半天也沒看出啥來,話說那些注釋是啥意思呢,啥Sa又Da,寶寶頭都大了?
網上看了一些文字解釋,原來這樣:
Sa->Source alpha->源圖的Alpha通道
Da->Destination alpha->目標圖的Alpha通道
Sc->Source color->源圖的顏色
Dc->Destination color ->目標圖的顏色
然後呢這樣混合過後就組成了最後的ARGB值,形成最終的效果
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved