一、Paint介紹
Paint畫筆,常與Canvas、Bitmap、Path等一起使用,用于繪制自定義View。Paint,儲存了繪制幾何圖形、文本和位圖的樣式和顔色資訊。常用的API也與顔色、效果(濾鏡、顔色混合)、文本相關。
二、Paint API
源碼中,Paint的方法内部都是調用的 native 方法。
-
構造方法。Paint有三個構造方法,一個無參構造方法 Paint(),兩個有參構造方法Paint(int flags)、Paint(Paint paint)。**Paint()**調用的是 flag為0的 Paint(int flags)方法;Paint(Paint paint) 方法傳入一個Paint對象,将傳入的Paint對象的參數賦予新的Paint對象; Paint(int flags) 參數有:
1.1 ANTI_ALIAS_FLAG 抗鋸齒。
1.2 FILTER_BITMAP_FLAG 在縮放的位圖上啟用雙線性采樣。
1.3 DITHER_FLAG 在繪制時啟用抖動。
1.4 UNDERLINE_TEXT_FLAG 文本加下劃線。
1.5 STRIKE_THRU_TEXT_FLAG 文本上加橫線。
1.6 FAKE_BOLD_TEXT_FLAG 文本粗體。
1.7 LINEAR_TEXT_FLAG 文本的平滑線性縮放。啟用此标志實際上不會縮放文本,而是調整文本繪制操作以優雅地處理縮放比例。啟用此标志時,将禁用字型提示以防止縮放因子之間的形狀變形,并且由于将生成大量字形圖像而禁用字形緩存。應該與 SUBPIXEL_TEXT_FLAG标志一起使用,以防止字形位置在調整比例因子時捕捉到整個像素值。
1.8 SUBPIXEL_TEXT_FLAG 用于啟用子像素定位文本。
1.9 EMBEDDED_BITMAP_TEXT_FLAG 在繪制文本時使用位圖字型。
1.10 HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG。HIDDEN_DEFAULT_PAINT_FLAGS 是所有Paint都建立的時候一定會預設設定的flag,其中DEV_KERN_TEXT_FLAG是标注不在使用的flag,不管他,EMBEDDED_BITMAP_TEXT_FLAG 是在繪制文本時使用位圖字型的設定,表示所有的paint對象都預設有這個設定。
-
顔色相關:
2.1 setColor(Color.RED) 設定顔色
2.2 setARGB(255, 255, 255, 0) 設定 Paint對象顔色,範圍為0~255
2.3 setAlpha(200) 設定alpha不透明度,範圍為0~255
2.4 setColorFilter(colorFilter) 設定顔色過濾
-
樣式相關:
3.1 **setAntiAlias(true)**抗鋸齒
3.2 setStyle(Paint.Style.FILL) 描邊效果 有三種參數:FILL(填充,預設效果)、STROKE(描邊)、FILL_AND_STROKE(填充加描邊)
3.3 setStrokeWidth(4) 描邊寬度
3.4 setStrokeCap(Paint.Cap.ROUND) 圓角效果 有三種參數:BUTT(預設效果)、ROUND(圓形)、SQUARE(方形)
3.5 setStrokeJoin(Paint.Join.MITER) 拐角風格 MITER(斜切,預設),ROUND(圓角)、BEVEL(斜角) -
濾鏡
4.1 setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)) 設定渲染器 此方法可設定多種渲染器,這裡是環形渲染器,渲染器相關在後文會較長的描述。
4.2 setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)) 設定圖層混合模式 後文詳述。
4.3 setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)) 設定顔色過濾器 後文詳述。
4.4 setFilterBitmap(true) 設定雙線性過濾 使圖檔效果更加平滑。效果如下圖
4.5 setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL)) 設定畫筆遮罩濾鏡,傳入半徑和樣式,可設定文字和圖檔的遮罩,樣式種類:NORMAL、SOLID、OUTER、INNER -
字型
5.1 setTextScaleX(2) 設定文本縮放倍數
5.2 setTextSize(38) 設定字型大小
5.3 setTextAlign(Paint.Align.LEFT) 設定對齊方式
5.4 setUnderlineText(true) 設定下劃線
5.5 getTextBounds(str, 0, str.length(), rect) 測量文本大小,将文本大小資訊存放在rect中
5.6 measureText(str) 擷取文本的寬
5.7 getFontMetrics() 擷取字型度量對象
三、各種濾鏡(Paint顔色處理)
- 前兩種方式比較簡單就不贅述了。
-
第三種設定着色器。Shader有5個子類:
2.1 LinearGradient(線性漸變器)。構造方法:LinearGradient(float x0, float y0, float x1, float y1, int colors[],float positions[], TileMode tile)------x0,y0漸變開始點坐标,x1,y1漸變結束點坐标,colors顔色數組和後面的positions數組對應,positions數組數值都在0-1之間,表示前面的顔色數組開始漸變的位置,可以傳null,tile用于指定控件區域大于漸變區域時,空白區域的填充方式。
2.2 RadialGradient(圓形渲染器)。構造方法:RadialGradient(float centerX, float centerY, float radius,int colors[], float stops[],TileMode tileMode)------centerX,centerY輻射中心的坐标,radius 輻射半徑,centerColor輻射中心的顔色,edgeColor輻射邊緣的顔色,tileMode輻射範圍之外的着色規則。
2.3 SweepGradient(掃描渲染)。構造方法:SweepGradient(float cx, float cy, int color0, int color1)------cx,cy掃描的中心,color0掃描的起始顔色,color1掃描的終止顔色。
2.4 BitmapShader(位圖渲染)。構造方法:BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)------bitmap用來做模版的bitmap,tileX橫向的着色規則,tileY縱向着色規則。
2.5 ComposeShader(組合渲染)。構造方法:ComposeShader( Shader shaderA, Shader shaderB, Xfermode mode);ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode);shaderA,shaderB:要混合的兩種shader,Xfermode mode: 組合兩種shader顔色的模式(Xfermode 中包含PorterDuff.Mode 的設定,即,最終還是PorterDuff.Mode 設定兩個渲染器疊加模式),PorterDuff.Mode mode: 組合兩種shader顔色的模式
-
TileMode
3.1 CLAMP 當canvas大于渲染器的位置時,按最後一個像素鋪開未覆寫區域。
3.2 REPEAT 當canvas大于渲染器的位置時,重複處理。
3.3 MIRROR 當canvas大于渲染器的位置時,鏡像處理。
-
Xfermode 圖層混合
4.1 GitHub上有個Google的Api示例,GoogleApiDemo。上面在app/src/maim/java/com/example/android/apis/graphics/Xfermodes.java中有Xfermode相關的代碼實作。這裡取其中的模式種類代碼和實作結果截圖,來解釋Xfermode各種模式的實作效果:
//效果作用于src源圖像區域
private static final Xfermode[] sModes = {
//所繪制不會送出到畫布上
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
//顯示上層繪制的圖像
new PorterDuffXfermode(PorterDuff.Mode.SRC),
//顯示下層繪制圖像
new PorterDuffXfermode(PorterDuff.Mode.DST),
//正常繪制顯示,上下層繪制疊蓋
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
//上下層都顯示,下層居上顯示
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
//取兩層繪制交集,顯示上層
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
//取兩層繪制交集,顯示下層
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
//取上層繪制非交集部分,交集部分變成透明
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
//取下層繪制非交集部分,交集部分變成透明
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
//取上層交集部分與下層非交集部分
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
//取下層交集部分與上層非交集部分
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
//去除兩圖層交集部分
new PorterDuffXfermode(PorterDuff.Mode.XOR),
//取兩圖層全部區域,交集部分顔色加深
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
//取兩圖層全部區域,交集部分顔色點亮
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
//取兩圖層交集部分,顔色疊加
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
//取兩圖層全部區域,交集部分濾色
new PorterDuffXfermode(PorterDuff.Mode.SCREEN),
//取兩圖層全部區域,交集部分飽和度相加
new PorterDuffXfermode(PorterDuff.Mode.ADD),
//取兩圖層全部區域,交集部分疊加
new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)
};
圖層混合時需調用禁止硬體加速方法,圖層混合有些api不支援硬體加速
禁止硬體加速方法(使用一個bitmap進行緩沖):setLayerType(LAYER_TYPE_SOFTWARE, mPaint);
三處使用圖層混合的地方:ComposeShader(Paint的組合渲染)、paint.xfermode(Paint的圖層混合設定)、 PorterDuffColorFilter(顔色過濾器,一種濾色鏡,可用于使用單一顔色和特定顔色對源像素進行着色)
注意:禁止硬體加速和設定背景色不能放在onDraw方法裡,會導緻onDraw方法多次調用,禁止硬體加速–>onDraw不停調用(log刷屏),設定背景顔色–>onDraw兩次調用
-
LightingColorFilter 設定顔色濾鏡,可以調整圖檔的色調。
構造方法:LightingColorFilter( int mul, int add),兩個參數與顔色的計算方法:R*mul + R +add = R;RGB三個值都這樣計算,mul和add值樣例:0x00ffff,十六進制,當mul的高兩位是00時,表示紅色被過濾了,中間兩位為00,綠色被過濾,低兩位表示藍色被過濾,mul和add混合着可以調節圖檔色調
-
PorterDuffColorFilter 設定顔色和圖檔混合,設定混合模式。
構造方法:PorterDuffColorFilter(int color, PorterDuff.Mode mode) color表示設定顔色濾鏡,mode是Xfermode混合模式,參數見上文的Xfermode[]。
- ColorMatrixColorFilter 使用顔色矩陣修改圖檔顔色,
p圖軟體的各種濾鏡效果都可以用這種矩陣實作,例如膠片、電影等濾鏡效果。
有個ColorMatrix的類,定義了各種方法操作矩陣:
7.1 colorMatrix.setScale(1,1,1,1); 亮度調節。參數傳入1表示原圖,四個參數分别表示RGBA的值。
7.2 colorMatrix.setSaturation(1); 飽和度調節 0-無色彩,1-預設,>1飽和度加強
7.3 colorMatrix.setRotate(int axis, float degrees); axis顔色通道 0-R,1-G,2-B,degrees顔色在三角坐标旋轉的角度,這裡就不詳述了,具體的可以百度一下這一塊詳解的文章
四、離屏繪制
//離屏繪制
int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
//todo 進行繪制
canvas.restoreToCount(layerId);
離屏繪制時,對canvas進行的操作都不會影響到目前的canvas上。
離屏緩沖,也通俗地稱之為層,這個概念很簡單,我們在繪圖的時候建立一個“層”,所有的繪制操作都在該層上而不影響該層以外的圖像,比如代碼中我們在繪制了畫布顔色和左右上方兩個方形後就建立了一個圖層來繪制中間的大正方形,這個方形和左右上方的方形是在兩個不同的層上的。很類似PS中的層。詳解Paint的setXfermode(Xfermode xfermode)
圖層混合要配合離屏緩沖一起使用,避免圖層混合出現混亂。在離屏緩沖繪制完成時要用mPaint.setXfermode(null);方法清除混合模式。
View.setLayerType()将整個View設定離屏緩沖。