Paint基本使用

(1)構造方法和flag標誌
//創建默認設置的畫筆
public Paint() 
//創建指定標記的畫筆,類似於給畫筆取了個名字
public Paint(int flags) 
//創建和現有畫筆屬性相同的畫筆
public Paint(Paint paint) 

其中第二個構造方法的參數flags代表Paint標誌,下面列出Paint的標誌(這個一般只要瞭解就行了,開發中Paint標誌用到的很少,大部分)

//抗鋸齒標誌,對應的方法是mPaint.setAntiAlias(true),一些圖畫出來之後可以很明顯的看出鋸齒的存在,加上這句話可以基本消除鋸齒
public static final int ANTI_ALIAS_FLAG = 1;
//使位圖過濾的位掩碼標誌(對位圖進行濾波),對應的方法是mPaint.setFilterBitmap(true),可以消除bitmap的濾波
public static final int FILTER_BITMAP_FLAG = 2;
//使位圖進行有利的抖動的位掩碼標誌(抖動處理),對應的方法是mPaint.setDither(true),可以讓圖像看起來更加柔和
public static final int DITHER_FLAG = 4;
//給文字添加下劃線,對應的方法是mPaint.setUnderlineText(true)
public static final int UNDERLINE_TEXT_FLAG = 8;
//給文字添加刪除線,對應的方法是mPaint.setStrikeThruText(true)
public static final int STRIKE_THRU_TEXT_FLAG = 16;
//文字加粗,對應的方法是mPaint1.setFakeBoldText(true)
public static final int FAKE_BOLD_TEXT_FLAG = 32;
//使文本平滑線性擴展的油漆標誌
public static final int LINEAR_TEXT_FLAG = 64;
//使文本的亞像素定位的繪圖標誌
public static final int SUBPIXEL_TEXT_FLAG = 128;
//遺棄的畫筆標誌,不用管
public static final int DEV_KERN_TEXT_FLAG = 256;
//繪製文本時允許使用位圖字體的繪圖標誌
public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024;
//畫筆隱藏模式關閉
public static final int HINTING_OFF = 0;
//畫筆隱藏模式打開
public static final int HINTING_ON = 1;
(2)設置畫筆的樣式
setStyle(Paint.Style style) 

設置畫筆樣式,取值有

Paint.Style.FILL :填充內部
Paint.Style.FILL_AND_STROKE :填充內部和描邊
Paint.Style.STROKE :僅描邊、
(3)設置畫筆的寬度
setStrokeWidth(float width) 
(4)設置畫筆是否抗鋸齒
setAntiAlias(boolean aa) 
(5)設置線冒樣式
setStrokeCap(Paint.Cap cap)

設置線冒樣式,取值有

Cap.ROUND(圓形線冒)
Cap.SQUARE(方形線冒)
Paint.Cap.BUTT(無線冒) 

注意:冒多出來的那塊區域就是線帽!就相當於給原來的直線加上一個帽子一樣,所以叫線帽

如圖所示:

第一個是無線帽,第二個是圓形線帽,第三個是方形線帽。

(6)設置線段連接處樣式
setStrokeJoin(Paint.Join join)

如果不設置setStrokeJoin,那麼線段的連接處默認是尖角


只有當角度太小時,Android爲了防止尖角的延長線過長,自己做了處理,尖角變成了平角,如圖:

下面我來說明一下setStrokeJoin的三種樣式:

Join.MITER(結合處爲尖角)

注意: 雖然設置了拐角處爲尖角,但是如果角度太小,Android依然會將尖角變成平角。

Join.Round(結合處爲圓弧)
Join.BEVEL(結合處爲平角) 
(7)設置 MITER 型拐角的延長線的最大值

這個方法是對於 setStrokeJoin() 的一個補充,它用於設置 MITER 型拐角的延長線的最大值。(如果沒有設置setStrokeJoin,則拐角默認是尖角)

setStrokeMiter(float miter) 

miter的默認值是4。我們來看下圖:

miter >=b / a;

也就是說,當 b/a<=miter時,依然顯示尖角,如果b/a > miter,尖角就會變成平角,這時a和b也隨之變化。

如果一但從尖角變成平角,那麼 miter = b / a。

當我們設置miter時,比如:從默認值4改成2

    mPaint.setStrokeMiter(2);

那麼miter =2, b / a的最大值就是2,如果 b / a超過2,那麼尖角就會變成平角。

(8)清空畫筆復位
void reset() 

重置 Paint 的所有屬性爲默認值。相當於重新 new 一個。

(9)設置一個外來Paint畫筆
void set(Paint src) 
(10)獲取與設置alpha值、顏色、ARGB
setARGB(int a, int r, int g, int b) 
getAlpha() 
setAlpha(int a) 
getColor() 
setColor(int color)
(11)獲取與設置是否使用抗鋸齒功能
isAntiAlias() 
setAntiAlias(boolean aa) 

會消耗較大資源,繪製圖形速度會變慢,一般會開啓。設置後會平滑一些
final boolean isDither()

(12)獲取與設定是否使用圖像抖動處理
setDither(boolean dither) 

會使繪製出來的圖片顏色更加平滑和飽滿、圖像更加清晰。

(13)setPathEffect(PathEffect effect)

設置繪製路徑的效果

基本代碼如下:

    setLayerType(View.LAYER_TYPE_SOFTWARE, null);//關閉硬件加速

    mPaint.setColor(Color.BLACK);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeWidth(5);

    canvas.drawLine(0, 200, canvas.getWidth(), 200, mPaint);
    canvas.drawLine(200, 0, 200, canvas.getHeight(), mPaint);

    canvas.translate(200, 200);//將畫布移動到(100,100)位置

    mPaint.setPathEffect(new PathEffect());
    mPaint.setColor(Color.BLUE);

    Path path = new Path();
    path.moveTo(-180, 50);
    path.lineTo(-150, -50);
    path.lineTo(-120, -10);
    path.lineTo(-100, -70);
    path.lineTo(-80, -40);
    path.lineTo(-40, 10);
    path.lineTo(-20, -10);
    path.lineTo(0, 50);
    path.lineTo(20, -20);
    path.lineTo(50, 70);
    path.lineTo(100, 10);
    path.lineTo(120, -10);
    path.lineTo(150, 60);
    path.lineTo(200, -70);
    path.lineTo(220, -10);
    path.lineTo(250, 0);
    path.lineTo(280, -70);
    path.lineTo(300, 70);
    path.lineTo(330, 10);
    path.lineTo(360, -100);
    path.lineTo(380, 10);
    path.lineTo(400, -70);
    canvas.drawPath(path, mPaint);

    mPaint.reset();

此時Path是沒有任何效果的,演示圖如下

下面分別介紹Path效果

  • CornerPathEffect——圓形拐角效果

      mPaint.setPathEffect(new CornerPathEffect(50));
    

    利用半徑R=50的圓來代替原來兩條直線間的夾角。

效果如下:

  • DashPathEffect——虛線效果
//畫同一條線段,偏移值爲phase  
mPaint.setPathEffect(new DashPathEffect(new float[]{10,5,6,15},phase));

intervals[]:表示組成虛線的各個線段的長度;整條虛線就是由intervals[]中這些基本線段循環組成的。比如,我們定義new float[] {20,10};那這個虛線段就是由兩段線段組成的,第一個可見的線段長爲20,每二個線段不可見,長度爲10;
phase:開始繪製的偏移值。

效果圖如下

如果在onDraw處添加以下兩句代碼會產生動畫效果

    phase ++;
    invalidate();
  • PathDashPathEffect——虛線效果

DashPathEffect類似,也是虛線效果,不同的是PathDashPathEffect可以讓我們自己定義路徑虛線的樣式。

PathDashPathEffect(Path shape, float advance, float phase, Style style)

shape:虛線點的填充圖形
advance:shape和shape之間的間隔
phase:開始繪製的偏移量,結合invalidate()同樣有動畫效果
style:虛線連接處的樣式,現有三種樣式
PathDashPathEffect.Style.MORPH: 圖形會以發生拉伸或壓縮等變形的情況與下一段相連接
PathDashPathEffect.Style.ROTATE: 線段連接處的圖形轉換以旋轉到與下一段移動方向相一致的角度進行連接
PathDashPathEffect.Style.TRANSLATE: 圖形會以位置平移的方式與下一段相連接

DashPathEffect可以設置虛線不同線段的長度,但是PathDashPathEffect不行,PathDashPathEffect的優勢在於可以設置虛線的圖形。

    Path shape = new Path();
    RectF rectF = new RectF();
    rectF.left = 0;
    rectF.top = 0;
    rectF.right = 10;
    rectF.bottom = 10;
    shape.addCircle(0, 0, 5, Path.Direction.CW);
    mPaint.setPathEffect(new PathDashPathEffect(shape, 20, phase, PathDashPathEffect.Style.TRANSLATE));

添加如上代碼的效果圖如下:

添加一下代碼可以實現動畫效果:

    phase ++;
    invalidate();
  • DiscretePathEffect——離散路徑效果
DiscretePathEffect(float segmentLength, float deviation)

其構造方法有兩個參數:

segmentLength: 每隔segmentLength都會有一個突出點;

deviation: 突出點的偏移量;

mPaint.setPathEffect(new DiscretePathEffect(3, 10));

每隔距離爲3的地方都會出現偏移量爲10的突出點。

它同樣也能做出動畫效果

    if(deviation > 10){
        deviation = 0;
    }

    deviation = deviation + 0.02f;

    invalidate();
  • ComposePathEffect——組合路徑效果
ComposePathEffect(PathEffect outerpe, PathEffect innerpe)

組合方式是:先將路徑變成innerpe的效果,再去複合outerpe的路徑效果,即:outerpe(innerpe(Path))

    PathEffect dashPathEffect= new DashPathEffect(new float[]{10,5,6,15},5);

    PathEffect discretePathEffect = new DiscretePathEffect(3, 10);

    mPaint.setPathEffect(new ComposePathEffect(dashPathEffect, discretePathEffect));

效果如下:

  • SumPathEffect——疊加路徑效果
SumPathEffect(PathEffect first, PathEffect second)

組合方式是:將兩種合二爲一

    PathEffect dashPathEffect= new DashPathEffect(new float[]{10,5,6,15},5);

    PathEffect discretePathEffect = new DiscretePathEffect(3, 10);

    mPaint.setPathEffect(new SumPathEffect(dashPathEffect, discretePathEffect));
(14)setXfermode(Xfermode xfermode)

設置圖形重疊時的處理方式,如合併,取交集或並集,經常用來製作橡皮的擦除效果。

Xfermode 詳解

(15)setMaskFilter(MaskFilter maskfilter)

設置MaskFilter,可以用不同的MaskFilter實現濾鏡的效果,如濾化,立體等。

如圖所示,有兩種濾鏡需要我們去實驗

  • BlurMaskFilter-----模糊遮罩濾鏡 (改變圖像的透明度值來實現的)
BlurMaskFilter(float radius, Blur style)

radius: 半徑從原始遮罩延伸模糊的半徑;
style: 模糊樣式;

模糊樣式可分爲以下四種:

NORMAL: 在原始邊界內外模糊。
SOLID: 在邊界內繪製實體,在邊界外模糊。
OUTER: 在邊界內不繪製任何內容,在邊界外模糊。
INNER: 在邊界內模糊,在邊界外不繪製任何內容。

現在繪製一張圖片,圖片原始效果如下:

//使用NORMAL樣式
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.NORMAL));

使用NORMAL樣式的效果圖如下:

//使用SOLID樣式
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.SOLID));

使用SOLID樣式的效果圖如下:

//使用OUTER樣式
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.OUTER));

使用OUTER樣式的效果圖如下:

//使用INNER樣式
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.INNER));

使用INNER樣式的效果圖如下:

  • EmbossMaskFilter----浮雕遮罩濾鏡(類似於燈光照射效果)

      //指定光源的位置,長度爲xxx的數組標量[x,y,z]
      float[] direction = new float[] { 1, 1, 1 };
      // 環境光的因子 (0~1),越接近0,環境光越暗
      float light = .03f;
      // 鏡面反射係數 越接近0,鏡面反射越強
      float specular = 60;
      //模糊半徑 值越大,模糊效果越明顯
      float blur = 80f;
    
      EmbossMaskFilter emboss = new EmbossMaskFilter(direction, light, specular, blur);
      mPaint.setMaskFilter(emboss);
      canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.pic_shi), 0, 0, mPaint);
    
(16)setColorFilter(ColorFilter colorfilter)(顏色過濾器)

設置顏色過濾器,可以在繪製顏色時實現不用顏色的變換效果。

ColorFilter有三個子類,分別是LightingColorFilterPorterDuffColorFilterColorMatrixColorFilter

在講解這三種顏色過濾器之前,首先對RGB和ARGB做個普及。

顏色有三個通道,分別是R(紅色)、G(綠色)、B(藍色),在Android中,我們通常使用16進製表示一個RBG,比如:
紅色:#ff0000
綠色:#00ff00
藍色:#0000ff
黃色:#ffff00

該16進制有6爲,前兩位代表紅色通道,中間兩位代表綠色通道,後面兩位代表藍色通道。

如果加上透明度的話,就是所謂的ARGB,ARGB中的A是alpha(透明度)的意思,用8位16進製表示,比如:

100%透明度的紅色:#ffff0000
0%透明度的紅色:#00ff0000

其中前兩位代表透明度,#ff代表不透明,#00代表完全透明。

關於透明度和對應的顏色值,請看下錶

透明度 顏色(16進制)
100% FF
95% F2
90% E6
85% D9
80% CC
75% BF
70% B3
65% A6
60% 99
55% 8C
50% 80
45% 73
40% 66
35% 59
30% 4D
25% 40
20% 33
15% 26
10% 1A
5% 0D
0% 00

下面開始講解三種顏色過濾器。

  • LightingColorFilter

這個 LightingColorFilter 是用來模擬簡單的光照效果的。其構造方法如下:

LightingColorFilter(@ColorInt int mul, @ColorInt int add)

創建一個顏色過濾器,將RGB通道乘以一種顏色,然後添加第二種顏色。mul和add的alpha分量參數被忽略。

【解析開始】:

假如有一張圖,這張圖的色彩由R、G、B三種通道組成,這張圖展示如下:

  1. 現在我想去除紅色

    mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#00ffff"), Color.parseColor("#000000")));

其計算方式如下:

R' = R * 0x00 / 0xff + 0x0 = R  
G' = G * 0xff / 0xff + 0x0 = G 
B' = B * 0xff / 0xff + 0x0 = B 

效果如下:

  1. 去除綠色

    mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#ff00ff"), Color.parseColor("#000000")));

其計算方式如下:

R' = R * 0xff / 0xff + 0x0 = R  
G' = G * 0x00 / 0xff + 0x0 = G 
B' = B * 0xff / 0xff + 0x0 = B 

效果圖如下:

  1. 去除藍色

    mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#ffff00"), Color.parseColor("#000000")));

其計算方式如下:

R' = R * 0xff / 0xff + 0x0 = R  
G' = G * 0xff / 0xff + 0x0 = G 
B' = B * 0x00 / 0xff + 0x0 = B 

效果圖如下

  1. 讓紅色更亮一些
mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#ffffff"), Color.parseColor("#300000")));

其計算方式如下:

R' = R * 0xff / 0xff + 0x30 = R  
G' = G * 0xff / 0xff + 0x0 = G 
B' = B * 0xff / 0xff + 0x0 = B 

效果圖如下

  1. 讓綠色更亮一些
mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#ffffff"), Color.parseColor("#003000")));

其計算方式如下:

R' = R * 0xff / 0xff + 0x0 = R  
G' = G * 0xff / 0xff + 0x30 = G 
B' = B * 0xff / 0xff + 0x0 = B 

效果圖如下

  1. 讓藍色更亮一些
mPaint.setColorFilter(new LightingColorFilter(Color.parseColor("#ffffff"), Color.parseColor("#000030")));

其計算方式如下:

R' = R * 0xff / 0xff + 0x0 = R  
G' = G * 0xff / 0xff + 0x0 = G 
B' = B * 0xff / 0xff + 0x30 = B 

效果圖如下

  • PorterDuffColorFilter
mPaint.setColorFilter(new PorterDuffColorFilter(Color.parseColor("#ff0000"), PorterDuff.Mode.ADD));
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.pic_shi), 0, 0, mPaint);

這個 PorterDuffColorFilter 的作用是使用一個指定的顏色和一種指定的 PorterDuff.Mode 來與繪製對象進行合成。它的構造方法是 PorterDuffColorFilter(int color, PorterDuff.Mode mode) 其中的 color 參數是指定的顏色, mode 參數是指定的 Mode。同樣也是 PorterDuff.Mode ,不過和 ComposeShader 不同的是,PorterDuffColorFilter 作爲一個 ColorFilter,只能指定一種顏色作爲源,而不是一個 Bitmap。

有關PorterDuff.Mode的使用可以參考:PorterDuff.Mode詳解

  • ColorMatrixColorFilter

ColorMatrixColorFilter 使用一個 ColorMatrix 來對顏色進行處理。 ColorMatrix 這個類,內部是一個 4x5 的矩陣:

[ a, b, c, d, e,
  f, g, h, i, j,
 k, l, m, n, o,
 p, q, r, s, t ]

通過計算, ColorMatrix 可以把要繪製的像素進行轉換。對於顏色 [R, G, B, A] ,轉換算法是這樣的:

R’ = a*R + b*G + c*B + d*A + e;  
G’ = f*R + g*G + h*B + i*A + j;  
B’ = k*R + l*G + m*B + n*A + o;  
A’ = p*R + q*G + r*B + s*A + t; 

具體可以參考這篇博客實戰Android:圖片處理之ColorMatrix和Matrix實例

(17)setShader(Shader shader)(着色器、渲染器)

有關設置Android渲染器,請參考我的另外幾篇博客
Android之高級渲染Shader
使用LinearGradient實現文字輪播
使用SweepGradient實現雷達掃描效果

(18)setShadowLayer(float radius ,float dx,float dy,int color);

在圖形下面設置陰影層,產生陰影效果,radius爲陰影的模糊範圍,dx和dy爲陰影的偏移量,color爲陰影的顏色 。

    mPaint.setShadowLayer(50, 0, 0, Color.RED);

效果如下:

如果要清除陰影層,使用

    mPaint.clearShadowLayer();

需要特別注意的是:

  • 在硬件加速開啓的情況下, setShadowLayer() 只支持文字的繪製,文字之外的繪製必須關閉硬件加速才能正常繪製陰影。
  • 如果 shadowColor 是半透明的,陰影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的,陰影的透明度就使用 paint 的透明度。
(19)文字相關

文字相關的比較簡單,這裏就不一一介紹了。

float getFontSpacing() 
獲取字符行間距。

float getLetterSpacing() 
void setLetterSpacing(float letterSpacing) 
設置和獲取字符間距
        
final boolean isUnderlineText() 
void setUnderlineText(boolean underlineText) 
是否有下劃線和設置下劃線。

final boolean isStrikeThruText() 
void setStrikeThruText(boolean strikeThruText) 
獲取與設置是否有文本刪除線。
        
float getTextSize() 
void setTextSize(float textSize) 
獲取與設置文字大小,注意:Paint.setTextSize傳入的單位是px,TextView.setTextSize傳入的單位是sp,注意使用時不同分辨率處理問題。
        
Typeface getTypeface() 
Typeface setTypeface(Typeface typeface) 
獲取與設置字體類型。Android默認有四種字體樣式:BOLD(加粗)、BOLD_ITALIC(加粗並傾斜)、ITALIC(傾斜)、NORMAL(正常),我們也可以通過Typeface類來自定義個性化字體。
        
float getTextSkewX() 
void setTextSkewX(float skewX) 
獲取與設置文字傾斜,參數沒有具體範圍,官方推薦值爲-0.25,值爲負則右傾,爲正則左傾,默認值爲0。
        
Paint.Align getTextAlign() 
void setTextAlign(Paint.Align align) 
獲取與設置文本對齊方式,取值爲CENTER、LEFT、RIGHT,也就是文字繪製是左邊對齊、右邊還是局中的。

setSubpixelText(boolean subpixelText)
設置自像素。如果該項爲true,將有助於文本在LCD屏幕上的顯示效果。
固定的幾個範圍:320*480,480*800,720*1280,1080*1920等等;那麼如何在同樣的分辨率的顯示器中增強顯示清晰度呢?
亞像素的概念就油然而生了,亞像素就是把兩個相鄰的兩個像素之間的距離再細分,再插入一些像素,這些通過程序加入的像素就是亞像素。在兩個像素間插入的像素個數是通過程序計算出來的,一般是插入兩個、三個或四個。
所以打開亞像素顯示,是可以在增強文本顯示清晰度的,但由於插入亞像素是通過程序計算而來的,所以會耗費一定的計算機性能。
        
int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth) 
比如文本閱讀器的翻頁效果,我們需要在翻頁的時候動態折斷或生成一行字符串,這就派上用場了~

另外,有一篇博客寫的非常好,大家可以去看一下

HenCoder Android 開發進階: 自定義 View 1-2 Paint 詳解

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