Android自定義View---前奏篇(Paint和Canvas的使用)

本文轉自 http://blog.csdn.net/jiangwei0910410003/article/details/42640665,稍有修改,感謝分享!

在實現自定義View之前,有必要掌握Android中畫圖的相關類的使用方法,這是自定義各種酷炫界面的基礎。主要使用到以下兩個類:

  • 畫筆:Paint

  • 畫布:Canvas

1. Android中的Paint和Canvas的概念和使用方法

Android中的Paint和Canvas的概念是很簡單的,就是用畫筆在畫布上進行繪製,沒什麼難度的,只要拿到畫筆Paint和畫布Canvas對象就可以進行操作了。當然Canvas對象提供了很多繪製圖形的方法,

1.1 Paint對象

新建一個Paint畫筆對象

Paint p = new Paint();  
p.setColor(Color.RED);// 設置畫筆顏色爲紅色 
p.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了

注:關於這個鋸齒,其實很好理解,如果沒有鋸齒效果,畫出來的圓形就很光滑,有鋸齒看上去的圓形很粗糙的。但是默認情況下,畫筆是有鋸齒的。之所以這樣,是因爲在沒有鋸齒效果的情況下,繪製圖形效率會比有鋸齒效果低,所以系統考慮了效率問題,就把默認值設置成有鋸齒了,在實際繪圖過程中需要衡量一下的。

對於畫筆對象,它有很多的屬性:

  • void setARGB(int a, int r, int g, int b) //設置Paint對象顏色,參數一爲alpha透明通道
  • void setAlpha(int a) //設置alpha不透明度,範圍爲0~255
  • void setAntiAlias(boolean aa) //是否抗鋸齒,默認值是false
  • void setColor(int color) //設置顏色,這裏Android內部定義的有Color類包含了一些常見顏色定義
  • void setFakeBoldText(boolean fakeBoldText) //設置僞粗體文本
  • void setLinearText(boolean linearText) //設置線性文本
  • PathEffect setPathEffect(PathEffect effect) //設置路徑效果
  • Rasterizer setRasterizer(Rasterizer rasterizer) //設置光柵化
  • Shader setShader(Shader shader) //設置陰影 ,我們在後面會詳細說一下Shader對象的
  • void setTextAlign(Paint.Align align) //設置文本對齊
  • void setTextScaleX(float scaleX) //設置文本縮放倍數,1.0f爲原始
  • void setTextSize(float textSize) //設置字體大小
  • Typeface setTypeface(Typeface typeface) //設置字體,Typeface包含了字體的類型,粗細,還有傾斜、顏色等
    注:
    Paint mp = new paint();
    mp.setTypeface(Typeface.DEFAULT_BOLD)

    常用的字體類型名稱還有:

    • Typeface.DEFAULT //常規字體類型
    • Typeface.DEFAULT_BOLD //黑體字體類型
    • Typeface.MONOSPACE //等寬字體類型
    • Typeface.SANS_SERIF //sans serif字體類型
    • Typeface.SERIF //serif字體類型

    除了字體類型設置之外,還可以爲字體類型設置字體風格,如設置粗體:
    Paint mp = new Paint();
    Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
    p.setTypeface( font );

    常用的字體風格名稱還有:

    • Typeface.BOLD //粗體
    • Typeface.BOLD_ITALIC //粗斜體
    • Typeface.ITALIC //斜體
    • Typeface.NORMAL //常規
  • void setUnderlineText(boolean underlineText) //設置下劃線

  • void setStyle(Style style) //設置畫筆樣式
    常用的樣式:

    • Paint.Style.FILL
    • Paint.Style.STROKE
    • Paint.Style.FILL_AND_STROKE
      這裏的FILL和STROKE兩種方式用的最多,他們的區別也很好理解的,FILL就是填充的意思,STROKE就是空心的意思,只有 圖形的輪廓形狀,內部是空的。
  • void setStrokeWidth(float width) //在畫筆的樣式爲STROKE的時候,圖形的輪廓寬度

1.2 Canvas對象

對於畫布對象Canvas我們是從onDraw方法中獲取到的,我們在自定義視圖的時候都會繼承View類,然後在他的onDraw方法中拿到Canvas對象,進行各種繪製了。下面就來看一下各種繪製的方法:

1.2.1 畫圓(drawCircle)

想一下,如果畫出一個圓形的話需要哪些要素,學過幾何的同學都知道:圓心座標+半徑 就可以確定一個圓了

canvas.drawCircle(120, 20, 20, p); //這裏的p是之前講的Paint對象
  • 參數一:圓心的x座標
  • 參數二:圓心的y座標
  • 參數三:圓的半徑
  • 參數四:畫筆對象

1.2.2 畫直線(drawLine)

畫出一個直線,需要起點座標+終點座標 就可以確定一條直線了

canvas.drawLine(60, 40, 100, 40, p);// 畫直線  
  • 參數一:起始點的x座標
  • 參數二:起始點的y座標
  • 參數三:終點的x座標
  • 參數四:終點的y座標
  • 參數五:畫筆對象

1.2.3 畫矩形(drawRect)

RectF oval1=new RectF(150,20,180,40);  
canvas.drawRect(oval1, p); 
  • 參數一:矩形對象
  • 參數二:畫筆對象

這裏說一下RectF的相關知識:在繪圖中這個對象是十分重要的,它表示的是一個矩形,它有四個參數:
left, top, right, bottom
這四個值是相對於設備屏幕的起始點開始的。
比如上面的這個矩形,是這樣:

RectF oval1=new RectF(150,20,180,40); 

這裏寫圖片描述
矩形的左上角的座標是:(150,20)
矩形的右下角的座標是:(180,30)
那麼我們就知道這個矩形的寬是:180-150=30;高是:40-20=20

注:還有一個與RectF相關的對象:Rect,它也是四個參數,和RectF唯一的區別就是,Rect中的參數是float類型的,RectF中的參數是int類型的

1.2.4 畫圓角矩形(drawRoundRect)

RectF oval3 = new RectF(80, 260, 200, 300);// 新建一個矩形  
canvas.drawRoundRect(oval3, 20, 15, p);
  • 參數一:矩形大小
  • 參數二:圓角的x半徑
  • 參數三:圓角的y半徑
  • 參數四:畫筆對象

這裏寫圖片描述

1.2.5 畫橢圓(drawOval)

畫一個橢圓,需要的要素是長軸長度+短軸長度

RectF oval1=new RectF(150,20,180,40); //新建一個橢圓外接矩形
canvas.drawOval(oval2, p); 
  • 參數一:橢圓的外接矩形
  • 參數二:畫筆對象

一個矩形可以確定一個橢圓,這個矩形和橢圓外接
這裏寫圖片描述
橢圓的長軸就是矩形的寬短軸就是矩形的高
這樣就可以確定一個橢圓了,如果想畫一個圓形,用這種方式也是可以的,只要把RectF設置成正方形就可以了。

1.2.6 畫弧線/扇形(drawArc)

畫出一個弧線需要的要素是,起始的弧度+弧線的弧度+外圍的矩形大小
這個和上面畫橢圓很相似的,就相當於在他的基礎上多了 起始弧度+弧線的弧度

p.setStyle(Paint.Style.STROKE);//設置空心  
RectF oval1=new RectF(150,20,180,40);  
canvas.drawArc(oval1, 180, 180, false, p);//弧形  
  • 參數一:外接矩形
  • 參數二:弧線開始的弧度
  • 參數三:弧線的弧度
  • 參數四:是一個boolean類型的參數:true的時候畫扇形,是false的時候畫弧線
  • 參數五:畫筆對象

1.2.7 畫三角形/多邊形(drawPath)

畫三角形/多邊形需要的要素,能確定多邊形的形狀最重要的因素就是角,這些角的頂點就是一個座標

Path path = new Path();  
path.moveTo(80, 200);// 此點爲多邊形的起點  
path.lineTo(120, 250);  
path.lineTo(80, 250);  
path.close(); // 使這些點構成封閉的多邊形  
canvas.drawPath(path, p); 

這裏需要介紹一下Path對象,這個對象顧名思義,是路徑的意思,它有兩個參數:

  • 參數一:x座標
  • 參數二:y座標

路徑是由多個點相連接的。所以Path提供了兩個方法:moveTo()lineTo()

  • moveTo方法的作用是設置路徑的開始點,如果沒有這個方法的調用的話,系統默認的開始點是(0,0)
  • lineTo方法就是將路徑的上一個座標點和當前座標點進行連接,或者可以認爲設置多邊形的每個角的頂點的座標

那麼對於三角形,需要三個點即可。
這個畫三角形其實用上面的畫直線的方法也可以實現的,反過來也是,我們用Path對象也是可以畫出一條直線的,那麼他們的本質區別是:

  • 繪製路徑方式的焦點是角的頂點(座標點)
  • 繪製直線的方式的焦點是邊(長度)

1.2.8 畫點(drawPoint)

canvas.drawPoint(60, 390, p);//畫一個點  
canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//畫多個點  

這裏有兩個方法:
drawPoint(畫一個點)

  • 參數一:點的x座標
  • 參數二:點的y座標
  • 參數三:畫筆對象

drawPoints(畫多個點)

  • 參數一:多個點的數組
  • 參數二:畫筆對象

1.2.9 畫貝塞爾曲線(drawPath)

這種曲線其實我們在開發過程中很少用到,在圖形學中繪製貝塞爾曲線的時候,需要的要素是:起始點+控制點+終點

Path path2=new Path();  
path2.moveTo(100, 320);//設置Path的起點  
path2.quadTo(150, 310, 170, 400); //設置貝塞爾曲線的控制點座標和終點座標  
canvas.drawPath(path2, p);//畫出貝塞爾曲線  

它也是使用Path對象的。不過用的是quadTo()方法

  • 參數一:控制點的x座標
  • 參數二:控制點的y座標
  • 參數三:終點的x座標
  • 參數四:終點的y座標

需要注意的是,這裏是調用moveTo方法來確定開始座標,如果沒有調用這個方法,起始點座標默認是:(0,0)

1.2.10 繪製圖片(drawBitmap)

可以將bitmap對象貼到畫布上,也是很常用的一種用法

//畫圖片,就是貼圖  
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);  
canvas.drawBitmap(bitmap, 250,360, p);  
  • 參數一:圖片Bitmap對象
  • 參數二:圖片相對於設備屏幕的left值
  • 參數二:圖片相對於設備屏幕的top值
    注:可以把圖片認爲是一個矩形,因爲圖片本身是有長度和寬度的,所以這裏只需要矩形的左上角的座標點,就可以確定這張圖片在屏幕中的位置了。

上面就介紹完了Paint對象和Canvas對象,他們兩個是自定義視圖的基礎,所以這部分內容一定要掌握,當然這兩個對象沒什麼難度的,這些東西是很簡單的。

下面來看一下實例代碼:

package com.example.drawpathdemo;  

import android.annotation.SuppressLint;  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.LinearGradient;  
import android.graphics.Paint;  
import android.graphics.Path;  
import android.graphics.RectF;  
import android.graphics.Shader;  
import android.util.AttributeSet;  
import android.view.View;  

public class DrawView extends View {  

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

    public DrawView(Context context, AttributeSet attributeSet) {    
        super(context, attributeSet);    
    }  

    @SuppressLint("DrawAllocation")  
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        /* 
         * 方法 說明
         * drawRect 繪製矩形 drawCircle 繪製圓形 drawOval 繪製橢圓 drawPath 繪製任意多邊形 
         * drawLine 繪製直線 drawPoin 繪製點 
         */  
        // 創建畫筆  
        Paint p = new Paint();  
        p.setColor(Color.RED);// 設置紅色  

        canvas.drawText("畫圓:", 10, 20, p);// 畫文本  
        canvas.drawCircle(60, 20, 10, p);// 小圓  
        p.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,一看效果就明白了  
        canvas.drawCircle(120, 20, 20, p);// 大圓  

        canvas.drawText("畫線及弧線:", 10, 60, p);  
        p.setColor(Color.GREEN);// 設置綠色  
        canvas.drawLine(60, 40, 100, 40, p);// 畫線  
        canvas.drawLine(110, 40, 190, 80, p);// 斜線  
        //畫笑臉弧線  
        p.setStyle(Paint.Style.STROKE);//設置空心  
        RectF oval1=new RectF(150,20,180,40);  
        canvas.drawArc(oval1, 180, 180, false, p);//小弧形  
        oval1.set(190, 20, 220, 40);  
        canvas.drawArc(oval1, 180, 180, false, p);//小弧形  
        oval1.set(160, 30, 210, 60);  
        canvas.drawArc(oval1, 0, 180, false, p);//小弧形  

        canvas.drawText("畫矩形:", 10, 80, p);  
        p.setColor(Color.GRAY);// 設置灰色  
        p.setStyle(Paint.Style.FILL);//設置填滿  
        canvas.drawRect(60, 60, 80, 80, p);// 正方形  
        canvas.drawRect(60, 90, 160, 100, p);// 長方形  

        canvas.drawText("畫扇形和橢圓:", 10, 120, p);  
        /* 設置漸變色 這個正方形的顏色是改變的 */  
        Shader mShader = new LinearGradient(0, 0, 100, 100,  
                new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW,  
                        Color.LTGRAY }, null, Shader.TileMode.REPEAT); // 一個材質,打造出一個線性梯度沿著一條線。  
        p.setShader(mShader);  
        RectF oval2 = new RectF(60, 100, 200, 240);// 設置個新的長方形,掃描測量  
        canvas.drawArc(oval2, 200, 130, true, p);  
        // 畫弧,第一個參數是RectF:該類是第二個參數是角度的開始,第三個參數是多少度,第四個參數是true的時候畫扇形,是false的時候畫弧線  
        //畫橢圓,把oval改一下  
        oval2.set(210,100,250,130);  
        canvas.drawOval(oval2, p);  

        canvas.drawText("畫三角形:", 10, 200, p);  
        // 繪製這個三角形,你可以繪製任意多邊形  
        Path path = new Path();  
        path.moveTo(80, 200);// 此點爲多邊形的起點  
        path.lineTo(120, 250);  
        path.lineTo(80, 250);  
        path.close(); // 使這些點構成封閉的多邊形  
        canvas.drawPath(path, p);  

        //你可以繪製很多任意多邊形,比如下面畫六連形  
        p.reset();//重置  
        p.setColor(Color.LTGRAY);  
        p.setStyle(Paint.Style.STROKE);//設置空心  
        Path path1=new Path();  
        path1.moveTo(180, 200);  
        path1.lineTo(200, 200);  
        path1.lineTo(210, 210);  
        path1.lineTo(200, 220);  
        path1.lineTo(180, 220);  
        path1.lineTo(170, 210);  
        path1.close();//封閉  
        canvas.drawPath(path1, p);  
        /* 
         * Path類封裝複合(多輪廓幾何圖形的路徑 
         * 由直線段*、二次曲線,和三次方曲線,也可畫以油畫。drawPath(路徑、油漆),要麼已填充的或撫摸 
         * (基於油漆的風格),或者可以用於剪斷或畫畫的文本在路徑。 
         */  

        //畫圓角矩形  
        p.setStyle(Paint.Style.FILL);//充滿  
        p.setColor(Color.LTGRAY);  
        p.setAntiAlias(true);// 設置畫筆的鋸齒效果  
        canvas.drawText("畫圓角矩形:", 10, 260, p);  
        RectF oval3 = new RectF(80, 260, 200, 300);// 設置個新的長方形  
        canvas.drawRoundRect(oval3, 20, 15, p);//第二個參數是x半徑,第三個參數是y半徑  

        //畫貝塞爾曲線  
        canvas.drawText("畫貝塞爾曲線:", 10, 310, p);  
        p.reset();  
        p.setStyle(Paint.Style.STROKE);  
        p.setColor(Color.GREEN);  
        Path path2=new Path();  
        path2.moveTo(100, 320);//設置Path的起點  
        path2.quadTo(150, 310, 170, 400); //設置貝塞爾曲線的控制點座標和終點座標  
        canvas.drawPath(path2, p);//畫出貝塞爾曲線  

        //畫點  
        p.setStyle(Paint.Style.FILL);  
        canvas.drawText("畫點:", 10, 390, p);  
        canvas.drawPoint(60, 390, p);//畫一個點  
        canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//畫多個點  

        //畫圖片,就是貼圖  
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);  
        canvas.drawBitmap(bitmap, 250,360, p);  
    }  
}  

運行效果:
這裏寫圖片描述

2. Android中重要的概念:渲染對象Shader

參考資料:http://blog.csdn.net/t12x3456/article/details/10473225

爲什麼把Shader對象單獨拿出來說一下呢?因爲這個對象在對於我們處理圖形特效的時候是非常有用

Shader的直接子類:

  • BitmapShader : 位圖圖像渲染
  • LinearGradient : 線性渲染
  • RadialGradient : 環形渲染
  • SweepGradient : 掃描漸變渲染/梯度渲染
  • ComposeShader : 組合渲染,可以和其他幾個子類組合起來使用

是不是很像Animation及其子類的關係(AlphaAnimation,RotateAnimation,ScaleAnimation,TranslateAnimation, AnimationSet)
既有具體的渲染效果,也有渲染效果的組合

Shader類作爲基類主要是返回繪製時顏色的橫向跨度。其子類可以作用於Piant。通過 paint.setShader(Shader shader);來實現一些渲染效果。只作用於圖形不作用於bitmap。
構造方法爲默認的構造方法。

枚舉:

emun  Shader.TileMode 

定義了平鋪的3種模式:

  • static final Shader.TileMode CLAMP//邊緣拉伸.
  • static final Shader.TileMode MIRROR//在水平方向和垂直方向交替景象, 兩個相鄰圖像間沒有縫隙.
  • static final Shader.TillMode REPETA//在水平方向和垂直方向重複擺放,兩個相鄰圖像間有縫隙縫隙.

方法:

  • boolean getLoaclMatrix(Matrix localM); //如果shader有一個非本地的矩陣將返回true。localM:如果不爲null將被設置爲shader的本地矩陣.

  • void setLocalMatrix(Matrix localM); //設置shader的本地矩陣,如果localM爲空將重置shader的本地矩陣。

2.1 Shader的使用

使用步驟總結爲:

  1. 構建Shader對象
  2. 通過Paint的setShader方法設置渲染對象
  3. 設置渲染對象
  4. 繪製時使用這個Paint對象

2.1.1 BitmapShader的使用:

public BitmapShader(Bitmap bitmap,Shader.TileMode tileX,Shader.TileMode tileY)

調用這個方法來產生一個畫有一個位圖的渲染器(Shader)。

參數:

  • bitmap 在渲染器內使用的位圖
  • tileX The tiling mode for x to draw the bitmap in. 在位圖上X方向渲染器平鋪模式
  • tileY The tiling mode for y to draw the bitmap in. 在位圖上Y方向渲染器平鋪模式
  • TileMode:
    • CLAMP :如果渲染器超出原始邊界範圍,會複製範圍內邊緣染色。
    • REPEAT :橫向和縱向的重複渲染器圖片,平鋪。
    • MIRROR :橫向和縱向的重複渲染器圖片,這個和REPEAT重複方式不一樣,他是以鏡像方式平鋪。

實例代碼:

package com.tony.shader;  

import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.BitmapShader;  
import android.graphics.Canvas;  
import android.graphics.Paint;  
import android.graphics.Shader;  
import android.graphics.drawable.BitmapDrawable;  
import android.graphics.drawable.ShapeDrawable;  
import android.graphics.drawable.shapes.OvalShape;  
import android.util.AttributeSet;  
import android.view.View;  

public class BitmapShaderView extends View {  

    private BitmapShader bitmapShader = null;  
    private Bitmap bitmap = null;  
    private Paint paint = null;  
    private ShapeDrawable shapeDrawable = null;  
    private int BitmapWidth = 0;  
    private int BitmapHeight = 0;  

    public BitmapShaderView(Context context) {  
        super(context);  

        // 得到圖像  
        bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cat))  
                .getBitmap();  
        BitmapWidth = bitmap.getWidth();  
        BitmapHeight = bitmap.getHeight();  
        // 構造渲染器BitmapShader  
        bitmapShader = new BitmapShader(bitmap, Shader.TileMode.MIRROR,Shader.TileMode.REPEAT);  
    }  

    public BitmapShaderView(Context context,AttributeSet set) {  
        super(context, set);  
    }  

    @Override  
    protected void onDraw(Canvas canvas) {  
        // TODO Auto-generated method stub  
    super.onDraw(canvas);  
    //將圖片裁剪爲橢圓形      
        //構建ShapeDrawable對象並定義形狀爲橢圓      
        shapeDrawable = new ShapeDrawable(new OvalShape());    
        //得到畫筆並設置渲染器    
        shapeDrawable.getPaint().setShader(bitmapShader);    
        //設置顯示區域    
        shapeDrawable.setBounds(20, 20,BitmapWidth-140,BitmapHeight);    
        //繪製shapeDrawable    
        shapeDrawable.draw(canvas);    
    }  
}  

效果圖:
這裏寫圖片描述

2.1.2 LinearGradient的使用

相信很多人都看過歌詞同步的效果, 一是豎直方向的滾動,另一方面是水平方面的歌詞顏色漸變點亮效果,這種效果怎麼做呢? 這就需要用到LinearGradient線性渲染,下面還是先看具體的使用:

LinearGradient有兩個構造函數;

public LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile) 

參數:

  • float x0: 漸變起始點x座標
  • float y0:漸變起始點y座標
  • float x1:漸變結束點x座標
  • float y1:漸變結束點y座標
  • int[] colors:顏色 的int 數組
  • float[] positions: 相對位置的顏色數組,可爲null, 若爲null,顏色沿漸變線均勻分佈
  • Shader.TileMode tile: 渲染器平鋪模式
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,Shader.TileMode tile)

參數:

  • float x0: 漸變起始點x座標
  • float y0:漸變起始點y座標
  • float x1:漸變結束點x座標
  • float y1:漸變結束點y座標
  • int color0: 起始漸變色
  • int color1: 結束漸變色
  • Shader.TileMode tile: 渲染器平鋪模式

實例代碼:

package com.tony.shader;  

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

public class LinearGradientView extends View {  

    private LinearGradient linearGradient = null;    
    private Paint paint = null;    

    public LinearGradientView(Context context)    
    {    
        super(context);    
        linearGradient = new LinearGradient(0, 0, 100, 100, new int[] {    
                Color.YELLOW, Color.GREEN, Color.TRANSPARENT, Color.WHITE }, null,    
                Shader.TileMode.REPEAT);    
        paint = new Paint();    
    }    

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

    @Override  
    protected void onDraw(Canvas canvas) {  
        // TODO Auto-generated method stub  
        super.onDraw(canvas);  
        //設置渲染器  
        paint.setShader(linearGradient);    
                //繪製圓環  
        canvas.drawCircle(240, 360, 200, paint);   
    }  
}  

效果圖:
這裏寫圖片描述

關於這個渲染對象,需要多解釋一下,因爲這個渲染器用的地方很多:
具體看一下他的構造方法中的參數含義:

Paint paint2 = new Paint();  
paint2.setColor(Color.BLACK);  
paint2.setStrokeWidth(5);  
paint2.setStyle(Paint.Style.FILL);  
Shader mShader = new LinearGradient(0,0,100,100,  
        Color.RED,  
        Color.BLUE, Shader.TileMode.CLAMP);  
paint2.setShader(mShader);  
Rect rect = new Rect();  
rect.left = 0;  
rect.right = 300;  
rect.top = 0;  
rect.bottom = 300;  
canvas.drawRect(rect, paint2); 

效果圖:
這裏寫圖片描述

把構造方法中的值改變一下:

Shader mShader = new LinearGradient(0,0,300,300,  
        Color.RED,  
        Color.BLUE, Shader.TileMode.CLAMP);  

再看一下效果:
這裏寫圖片描述
這裏我們就看到了構造方法中的四個參數值的含義了:

  • 參數一:渲染開始點的x座標
  • 參數二:渲染開始點的y座標
  • 參數三:渲染結束點的x座標
  • 參數四:渲染結束點的y座標

因爲這裏設置矩形的大小是高和寬都是300
所以,從第一個例子中可以看出:渲染結束點之後的顏色是最後一種顏色:藍色

再將代碼改變一下:

Shader mShader = new LinearGradient(0,0,300,0,  
        Color.RED,  
        Color.BLUE, Shader.TileMode.CLAMP);  

效果:
這裏寫圖片描述

結束點的座標設置成:(300,0)就實現了橫向渲染
當然也可以實現縱向渲染的,這裏就不演示了。

再修改一下代碼:

Shader mShader = new LinearGradient(0,0,100,100,  
                Color.RED,  
                Color.BLUE, Shader.TileMode.MIRROR); 

效果:
這裏寫圖片描述
將渲染模式改成:Shader.TileMode.MIRROR 鏡像模式了
看到效果,當渲染結束點是(100,100)的時候,後面還是會繼續渲染的,而且是相反的(就像照鏡子一樣),然後再渲染一下,每次渲染的效果都是和之前的相反。因爲矩形的長度和寬度都是300,所以這裏會渲染三次。

再將代碼修改一下:

Shader mShader = new LinearGradient(0,0,100,100,  
                Color.RED,  
                Color.BLUE, Shader.TileMode.REPEAT);  

效果圖:

這裏寫圖片描述

將渲染模式改成:Shader.TileMode.REPEAT 重複模式了
這裏看到也是會渲染三次的,但是和鏡像模式不同的是,它們的渲染方向都是一致的。

從上面的三種渲染模式可以看出來,之後渲染的結束點小於渲染圖形的大小的時候纔會有效果的,如果把大小改一下:

Shader mShader = new LinearGradient(0,0,300,300,  
                Color.RED,  
                Color.BLUE, Shader.TileMode.REPEAT);  

效果圖:
這裏寫圖片描述
效果和Shader.TileMode.CLAMP一樣的。
這種渲染器用的地方還是很多的,後面介紹長條漸變的SeekBar就要用到這種渲染器

2.1.3 RadialGradient的使用

圓形渲染器,這種渲染器很好理解,就是同心圓的渲染機制

public RadialGradient(float x, float y, float radius, int[] colors, float[] positions,Shader.TileMode tile)

參數:

  • float x: 圓心X座標
  • float y: 圓心Y座標
  • float radius: 半徑
  • int[] colors: 渲染顏色數組
  • floate[] positions: 相對位置數組,可爲null, 若爲null,可爲null,顏色沿漸變線均勻分佈
  • Shader.TileMode tile:渲染器平鋪模式
public RadialGradient(float x, float y, float radius, int color0, int color1,Shader.TileMode tile)

參數:

  • float x: 圓心X座標
  • float y: 圓心Y座標
  • float radius: 半徑
  • int color0: 圓心顏色
  • int color1: 圓邊緣顏色
  • Shader.TileMode tile:渲染器平鋪模式

實例代碼:

package com.tony.shader;  

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

public class RadialGradientView extends View {  

    Paint mPaint = null;  
    // 環形漸變渲染  
    Shader mRadialGradient = null;  
    public RadialGradientView(Context context) {  
        super(context);  
        //1.圓心X座標2.Y座標3.半徑 4.顏色數組 5.相對位置數組,可爲null 6.渲染器平鋪模式   
        mRadialGradient = new RadialGradient(240, 240, 240, new int[] {    
                Color.YELLOW, Color.GREEN, Color.TRANSPARENT, Color.RED }, null,    
                Shader.TileMode.REPEAT);    
        mPaint = new Paint();    
    }  


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

     @Override    
        protected void onDraw(Canvas canvas) {    
            // 繪製環形漸變    
            mPaint.setShader(mRadialGradient);    
            // 第一個,第二個參數表示圓心座標    
            // 第三個參數表示半徑    
            canvas.drawCircle(240, 360, 200, mPaint);    
        }    
}  

效果:
這裏寫圖片描述

關於這個圓形渲染器,可以實現水波紋的效果:

package com.tony.testshader;  

import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.BitmapShader;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.RadialGradient;  
import android.graphics.Shader;  
import android.graphics.drawable.BitmapDrawable;  
import android.graphics.drawable.ShapeDrawable;  
import android.graphics.drawable.shapes.OvalShape;  
import android.util.AttributeSet;  
import android.util.DisplayMetrics;  
import android.view.MotionEvent;  
import android.view.View;  
/** 
 * 水波紋效果 
 * @author tony 
 * 
 */  

 public class WaterRipplesView extends View {  

    Shader mBitmapShader = null;  
    Bitmap mBitmapPn = null;  
    Paint mPaint = null;  
    Shader mRadialGradient = null;  
    Canvas mCanvas = null;  
    ShapeDrawable mShapeDrawable = null;  

    public WaterRipplesView(Context context) {  
        super(context);  

        // 初始化工作  
        Bitmap bitmapTemp = ((BitmapDrawable) getResources().getDrawable(  
                R.drawable.leaf)).getBitmap();  
        DisplayMetrics dm = getResources().getDisplayMetrics();  
        // 創建與當前使用的設備窗口大小一致的圖片  
        mBitmapPn = Bitmap.createScaledBitmap(bitmapTemp, dm.widthPixels,  
                dm.heightPixels, true);  
        // 創建BitmapShader object  
        mBitmapShader = new BitmapShader(mBitmapPn, Shader.TileMode.REPEAT,  
                Shader.TileMode.MIRROR);  
        mPaint = new Paint();  
    }  

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

    @Override  
    protected void onDraw(Canvas canvas) {  
        // TODO Auto-generated method stub  
        super.onDraw(canvas);  

        // 將圖片裁剪爲橢圓型  
        // 創建ShapeDrawable object,並定義形狀爲橢圓  
        mShapeDrawable = new ShapeDrawable(new OvalShape());// OvalShape:橢圓  
        // 設置要繪製的橢圓形的東西爲ShapeDrawable圖片  
        mShapeDrawable.getPaint().setShader(mBitmapShader);  
        // 設置顯示區域  
        mShapeDrawable.setBounds(0, 0, mBitmapPn.getWidth(),  
                mBitmapPn.getHeight());  
        // 繪製ShapeDrawable  
        mShapeDrawable.draw(canvas);  
        if (mRadialGradient != null) {  
            mPaint.setShader(mRadialGradient);  
            canvas.drawCircle(0, 0, 1000, mPaint);  
        }  
    }  

    // @覆寫觸摸屏事件  
    public boolean onTouchEvent(MotionEvent event) {  
        // @設置alpha通道(透明度)  
        mPaint.setAlpha(400);  
        mRadialGradient = new RadialGradient(event.getX(), event.getY(), 48,  
                new int[] { Color.WHITE, Color.TRANSPARENT },null, Shader.TileMode.REPEAT);  
        // @重繪  
        postInvalidate();  
        return true;  
    }  
}  

重寫觸發方法,獲取觸發點座標,設置渲染器的圓形座標,即可
效果:
這裏寫圖片描述

2.1.4 SweepGradient的使用

梯度渲染器,或者是扇形選擇器,和雷達掃描效果差不多

public SweepGradient(float cx, float cy, int[] colors, float[] positions)

參數:

  • cx: 渲染中心點x 座標
  • cy: 渲染中心y 點座標
  • colors: 圍繞中心渲染的顏色數組,至少要有兩種顏色值
  • positions: 相對位置的顏色數組,可爲null, 若爲null,可爲null,顏色沿漸變線均勻分佈
public SweepGradient(float cx, float cy, int color0, int color1)

參數:

  • cx: 渲染中心點x 座標
  • cy: 渲染中心點y 座標
  • color0: 起始渲染顏色
  • color1: 結束渲染顏色

實例代碼:

package com.tony.testshader;    


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


public class SweepGradientView extends View {    

    Paint mPaint = null;      
    // 梯度渲染      
    Shader mSweepGradient = null;      

    public SweepGradientView(Context context) {    
        super(context);    

         // 創建SweepGradient對象      
        // 第一個,第二個參數中心座標      
        // 後面的參數與線性渲染相同      
        mSweepGradient = new SweepGradient(240, 360, new int[] {Color.CYAN,Color.DKGRAY,Color.GRAY,Color.LTGRAY,Color.MAGENTA,      
                Color.GREEN,Color.TRANSPARENT, Color.BLUE }, null);      
        mPaint = new Paint();      
    }    



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


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

         // 繪製梯度漸變      
        mPaint.setShader(mSweepGradient);      

        canvas.drawCircle(240, 360, 200, mPaint);    
    }    
}  

效果圖:
這裏寫圖片描述

這種渲染器用到的地方很多,下一篇文章中的自定義圓形漸變的SeekBar就會用到這種渲染器

到此,自定義View需要使用的一些界面繪製相關類就介紹完,接下來將開始正式進入自定義View

注: 考慮到篇幅和內容相關性,將原博分成兩篇,再次感謝原作者! 原文鏈接:http://blog.csdn.net/jiangwei0910410003/article/details/42640665

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