目錄
- [Paint 之 Font](#Paint 之 Font)
姿勢點(diǎn)
- 在Android中設(shè)置數(shù)字類型的參數(shù)時(shí)如果沒有特別的說明膨更,參數(shù)的單位一般都為px像素。
- HardwareAccel 查看那些方法不支持硬件加速;
- 關(guān)閉硬件加速缴允,AndroidManifest.xml==> application節(jié)點(diǎn)下android:hardwareAccelerated=false
- 針對某個(gè)View關(guān)閉硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
- Android會(huì)把拷貝到資源目錄的圖片轉(zhuǎn)為RGB565
ColorFilter
** ColorMatrix**
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
});
- 行表示的R(紅色)的向量荚守,第二行表示的G(綠色)的向量,第三行表示的B(藍(lán)色)的向量练般,最后一行表示A(透明度)的向量
- 這個(gè)矩陣不同的位置表示的RGBA值矗漾,其范圍在0.0F至2.0F之間,1為保持原圖的RGB值;
- 每一行的第五列數(shù)字表示偏移值
Usage
// 生成色彩矩陣
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.5F, 0, 0, 0, 0, /*1表示不變顏色*/
0, 0.5F, 0, 0, 0,
0, 0, 0.5F, 0, 0,
0, 0, 0, 1, 0,
});
mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
數(shù)學(xué)原理是:
實(shí)踐效果
Demo1
// 生成色彩矩陣
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.5F, 0, 0, 0, 0,
0, 0.5F, 0, 0, 0,
0, 0, 0.5F, 0, 0,
0, 0, 0, 1, 0,
});
mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
Demo2
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.33F, 0.59F, 0.11F, 0, 0,
0.33F, 0.59F, 0.11F, 0, 0,
0.33F, 0.59F, 0.11F, 0, 0,
0, 0, 0, 1, 0,
});
Demo3
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
-1, 0, 0, 1, 1,
0, -1, 0, 1, 1,
0, 0, -1, 1, 1,
0, 0, 0, 1, 0,
});
Demo4
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0.393F, 0.769F, 0.189F, 0, 0,
0.349F, 0.686F, 0.168F, 0, 0,
0.272F, 0.534F, 0.131F, 0, 0,
0, 0, 0, 1, 0,
});
Demo5 紅色的變成了藍(lán)色而藍(lán)色的就變成了紅色
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
0, 0, 1, 0, 0,
0, 1, 0, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0,
});
LightingColorFilter
A color filter that can be used to simulate simple lighting effects.
[LightingColorFilter](http://developer.android.com/reference/android/graphics/LightingColorFilter.html#LightingColorFilter(int, int)) (int mul, int add)
R' = R * colorMultiply.R + colorAdd.R
G' = G * colorMultiply.G + colorAdd.G
B' = B * colorMultiply.B + colorAdd.B
usage:
//設(shè)置顏色過濾后為黃色
mPaint.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0X00FFFF00));
mPaint.setColorFilter(null); //還原本色
PorterDuffColorFilter
- Public Contructors
[PorterDuffColorFilter](http://developer.android.com/reference/android/graphics/PorterDuffColorFilter.html#PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode))(int color, PorterDuff.Mode mode) - PorterDuff.Mode 對應(yīng)
Paint.setXfermode(Xfermode xfermode)
AvoidXfermode
- API 16 以上機(jī)型必須在應(yīng)用或手機(jī)上關(guān)閉硬件加速 薄料;
- AvoidXfermode(int opColor, int tolerance, AvoidXfermode.Mode mode)
opColor:表示一個(gè)16進(jìn)制的可以帶透明通道的顏色值例如0x12345678
Tolerance:表示容差值敞贡,那么什么是容差呢?你可以理解為一個(gè)可以標(biāo)識(shí)“精確”或“模糊”的東西
AvoidXfermode.Mode: AvoidXfermode.Mode.AVOID或者AvoidXfermode.Mode.TARGET
AvoidXfermode.Mode.TARGET
在該模式下Android會(huì)判斷畫布上的顏色是否會(huì)有跟opColor不一樣的顏色摄职,比如我opColor是紅色誊役,那么在TARGET模式下就會(huì)去判斷我們的畫布上是否有存在紅色的地方,如果有谷市,則把該區(qū)域“染”上一層我們畫筆定義的顏色势木,否則不“染”色,而tolerance容差值則表示畫布上的像素和我們定義的紅色之間的差別該是多少的時(shí)候才去“染”的歌懒,比如當(dāng)前畫布有一個(gè)像素的色值是(200, 20, 13)啦桌,而我們的紅色值為(255, 0, 0),當(dāng)tolerance容差值為255時(shí)及皂,即便(200, 20, 13)并不等于紅色值也會(huì)被“染”色甫男,容差值越大“染”色范圍越廣反之則反.
Usage:
avoidXfermode = new AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.TARGET);
mPaint.setXfermode(avoidXfermode);
API 16+沒有關(guān)閉硬件加速
API 16以下關(guān)閉硬件加速
符合條件的效果,在我們的模式為TARGET容差值為0的時(shí)候此時(shí)只有當(dāng)圖片中像色顏色值為0XFFFFFFFF的地方才會(huì)被染色验烧,而其他地方不會(huì)有改變板驳,而當(dāng)容差值為255的時(shí)候只要是跟0XFFFFFFFF有點(diǎn)接近的地方都會(huì)被染色。
AvoidXfermode.Mode.AVOID
AVOID是我們指定的顏色是否與畫布不一樣
AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.AVOID):
當(dāng)模式為AVOID容差值為0時(shí)碍拆,只有當(dāng)圖片中像素顏色值與0XFFFFFFFF完全不一樣的地方才會(huì)被染色
AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.AVOID):
當(dāng)容差值為255時(shí)若治,只要與0XFFFFFFFF稍微有點(diǎn)不一樣的地方就會(huì)被染色
那么這玩意究竟有什么用呢慨蓝?比如說當(dāng)我們只想在白色的區(qū)域畫點(diǎn)東西或者想把白色區(qū)域的地方替換為另一張圖片的時(shí)候就可以采取這種方式!
PixelXorXfermode
- API 16以過時(shí)
- useless
- 概念最早來自于SIGGRAPH的Tomas Proter和Tom Duff
- 混合圖形的概念極大地推動(dòng)了圖形圖像學(xué)的發(fā)展端幼,延伸到計(jì)算機(jī)圖形圖像學(xué)像Adobe和AutoDesk公司著名的多款設(shè)計(jì)軟件都可以說一定程度上受到影響.
Usage:
paint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.SCREEN);
- Sa全稱為Source alpha表示源圖的Alpha通道礼烈;Sc全稱為Source color表示源圖的顏色;Da全稱為Destination alpha表示目標(biāo)圖的Alpha通道婆跑;Dc全稱為Destination color表示目標(biāo)圖的顏色此熬。
- “[……]”里分為兩部分 , 前代表計(jì)算后的Alpha通道,后代表計(jì)算后的顏色值滑进。
- More Alpha compositing wiki
PorterDuffXfermode高級(jí)姿勢
-
PorterDuff.Mode.ADD 計(jì)算方式:Saturate(S + D)犀忱;Chinese:飽和相加
- PorterDuff.Mode.CLEAR
- PorterDuff.Mode.DARKEN
計(jì)算方式:[Sa + Da - SaDa, Sc(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)];Chinese:變暗
兩個(gè)圖像混合扶关,較深的顏色總是會(huì)覆蓋較淺的顏色阴汇,如果兩者深淺相同則混合,如圖节槐,黃色覆蓋了紅色而藍(lán)色和青色因?yàn)槭歉该骰旌纤圆蛔?
- PorterDuff.Mode.DST_IN
兩張圖合成去掉美女頭上的字
// 先繪制dis目標(biāo)圖
canvas.drawBitmap(bitmapDis, x, y, mPaint);
// 設(shè)置混合模式
mPaint.setXfermode(PorterDuff.Mode.DST_IN);
// 再繪制src源圖
canvas.drawBitmap(bitmapSrc/*黑色底圖*/, x, y, mPaint);
// 還原混合模式
mPaint.setXfermode(null);
// 還原畫布
canvas.restoreToCount(sc);
- PorterDuff.Mode.DST_OUT
計(jì)算方式:[Da * (1 - Sa), Dc * (1 - Sa)]鲫寄;Chinese:只在源圖像和目標(biāo)圖像不相交的地方繪制目標(biāo)圖像
Paint 之 Font
FontMetrics
- Top: 是除了Baseline到字符頂端的距離外還應(yīng)該包含這些符號(hào)的高度,bottom類似 ;
- Android依然會(huì)在繪制文本的時(shí)候在文本外層留出一定的邊距疯淫,這就是為什么top和bottom總會(huì)比ascent和descent大一點(diǎn)的原因地来。而在TextView中我們可以通過xml設(shè)置其屬性android:includeFontPadding="false"去掉一定的邊距值但是不能完全去掉。
mFontMetrics = mPaint.getFontMetrics();
Log.d("Aige", "ascent:" + mFontMetrics.ascent);
Log.d("Aige", "top:" + mFontMetrics.top);
Log.d("Aige", "leading:" + mFontMetrics.leading);
Log.d("Aige", "descent:" + mFontMetrics.descent);
Log.d("Aige", "bottom:" + mFontMetrics.bottom);
StaticLayout結(jié)合TextPaint實(shí)現(xiàn)換行
mStaticLayout = new StaticLayout(TEXT, mTextPaint, canvas.getWidth(), Alignment.ALIGN_NORMAL, 1.0F, 0.0F, false);
mStaticLayout.draw(canvas);
Paint 之方法解析
- [breakText](http://developer.android.com/reference/android/graphics/Paint.html#breakText(java.lang.CharSequence, int, int, boolean, float, float[]))(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)
Measure the text, stopping early if the measured width exceeds maxWidth.
- measureForwards表示向前還是向后測量
- measuredWidth為一個(gè)可選項(xiàng)未斑,可以為空,不為空時(shí)返回真實(shí)的測量值
- 定義字體 Android中字體有四種樣式:BOLD(加粗),BOLD_ITALIC(加粗并傾斜),ITALIC(傾斜),NORMAL(正常)币绩;而其為我們提供的字體有五種:DEFAULT,DEFAULT_BOLD,MONOSPACE,SANS_SERIF和SERIF
//系統(tǒng)自帶
textPaint.setTypeface(Typeface.create("SERIF", Typeface.NORMAL));
textPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.NORMAL));
//自定義字體 一
createFromAsset(AssetManager mgr, String path)
createFromFile(String path)和createFromFile(File path)
//自定義字體 二
// 獲取字體并設(shè)置畫筆字體
Typeface typeface = Typeface.createFromAsset(context.getAssets(), "kt.ttf");
textPaint.setTypeface(typeface);
- setTextSkewX (float skewX) // 設(shè)置畫筆文本傾斜 官方推薦-0.25F
- setStrikeThruText (boolean strikeThruText) //文本刪除線
- setLinearText (boolean linearText)
設(shè)置是否打開線性文本標(biāo)識(shí)蜡秽,這玩意對大多數(shù)人來說都很奇怪不知道這玩意什么意思。想要明白這東西你要先知道文本在Android中是如何進(jìn)行存儲(chǔ)和計(jì)算的缆镣。在Android中文本的繪制需要使用一個(gè)bitmap作為單個(gè)字符的緩存芽突,既然是緩存必定要使用一定的空間,我們可以通過setLinearText (true)告訴Android我們不需要這樣的文本緩存董瞻。 - setFakeBoldText (boolean fakeBoldText) //設(shè)置文本仿粗體
** setMaskFilter(MaskFilter maskfilter) **
- 關(guān)閉硬件加速 setLayerType(LAYER_TYPE_SOFTWARE, null);
BlurMaskFilter
BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 是根據(jù)Alpha通道的邊界來計(jì)算模糊的
SOLID: 在圖像的Alpha邊界外產(chǎn)生一層與Paint顏色一致的陰影效果而不影響圖像本身,而NORMAL,OUTER和INNER,NORMAL會(huì)將整個(gè)圖像模糊掉:
- INNER效果其實(shí)并不理想寞蚌,實(shí)際應(yīng)用中我們使用的也少,我們往往會(huì)使用混合模式和漸變和獲得更完美的內(nèi)陰影效果钠糊。
- 從Bitmap中獲取其Alpha通道挟秤,在繪制Bitmap
// 獲取位圖的Alpha通道圖
shadowBitmap = srcBitmap.extractAlpha();
// 先繪制陰影
canvas.drawBitmap(shadowBitmap, x, y, shadowPaint);ps
// 再繪制位圖
canvas.drawBitmap(srcBitmap, x, y, null);
EmbossMaskFilter讓你繪制的圖像感覺像是從屏幕中“凸”起來更有立體感一樣(在設(shè)計(jì)軟件中類似的效果稱之為斜面浮雕)。
public EmbossMaskFilter (float[] direction, float ambient, float specular, float blurRadius)
- direction 指光照方向,有而且只能有三個(gè)值即float[x,y,z],
首先x和y很好理解抄伍,平面的兩個(gè)維度,上面小球使用[1,1] 45度角, 而z軸表示光源是在屏幕后方還是屏幕前方,上面我們是用的是1艘刚,正值表示光源往屏幕外偏移1個(gè)單位,負(fù)值表示往屏幕里面偏移截珍。[x,y,z]表示的是空間坐標(biāo)攀甚,代表光源的位置箩朴,那么一旦這個(gè)位置確定,[ax,ay,az]則沒有意義 - ambient 用來設(shè)置環(huán)境光的秋度,在Android中環(huán)境光默認(rèn)為白色炸庞,其值越大, 球陰影越淺
- specular是跟高光有關(guān)的,其值是個(gè)雙向值越小或越大高光越強(qiáng)中間值則是最弱
setPathEffect(PathEffect effect)
- ComposePathEffect(PathEffect outerpe, PathEffect innerpe)會(huì)先將路徑變成innerpe的效果静陈,再去復(fù)合outerpe的路徑效果燕雁,即:outerpe(innerpe(Path))诞丽;而SumPathEffect(PathEffect first, PathEffect second)則會(huì)把兩種路徑效果加起來再作用于路徑
setShadowLayer(float radius, float dx, float dy, int shadowColor)
- 該方法為我們繪制的圖形添加一個(gè)陰影層效果
- 同樣不支持HW
/**
* 初始化畫筆
*/
private void initPaint() {
// 實(shí)例化畫筆
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
mPaint.setStyle(Style.FILL);
mPaint.setShadowLayer(10, 3, 3, Color.DKGRAY);
}
Shader
BitmapShader
[BitmapShader](http://developer.android.com/reference/android/graphics/BitmapShader.html#BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode))(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
Usage:
mPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR));
Shader.TileMode
- 著色是先在Y軸拉伸了然后再沿著X軸重復(fù)對
LinearGradient
-
mPaint.setShader(new LinearGradient(left, top, right - RECT_SIZE, bottom - RECT_SIZE, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT)); //(left,top) 起點(diǎn)坐標(biāo)鲸拥, (right-RECT_SIZE, bottom-RECT_SIZE) 終點(diǎn)坐標(biāo),效果如下:
- LinearGradient(left, top, right, bottom, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, new float[] { 0, 0.1F, 0.5F, 0.7F, 0.8F }, Shader.TileMode.MIRROR)僧免,效果如下圖:
- new int[](colors[]) 定義漸變顏色
- new float[](positions[]) 定義漸變區(qū)間,取值區(qū)間[0, 100%]刑赶,意思是整個(gè)漸變占漸變區(qū)域的百分比
應(yīng)用案例圖片1——倒影:
// 實(shí)例化一個(gè)矩陣對象
Matrix matrix = new Matrix();
matrix.setScale(1F, -1F);
// 生成倒影圖
mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true);
//生產(chǎn)消失漸變
mPaint.setShader(
new LinearGradient(x, y + mSrcBitmap.getHeight(), x,
y + mSrcBitmap.getHeight() + mSrcBitmap.getHeight() / 4,
0xAA000000, Color.TRANSPARENT, Shader.TileMode.CLAMP));
//合成效果
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
public void onDraw(Canvas canvas){
canvas.draw(srcBitmap);
int sc = canvas.saveLayer(......,null,Canvas.ALL_SAVE_FLAG) ;
canvas.draw(mRefBitmap)
mPaint.setXfermode(mXfermode) ;
canvas.drawRect(left,top,right,bottom,mPaint) ;
mPaint.setXfermode(mXfermode);
canvas.restoreToCount(sc) ;
}
應(yīng)用案例圖片2-(去飽和、提亮懂衩、色相矯正)
姿勢訣竅第一式:
// 實(shí)例化混合模式
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SCREEN);
// 去飽和撞叨、提亮、色相矯正
mBitmapPaint.setColorFilter(new ColorMatrixColorFilter(
new float[] {
0.8587F, 0.2940F, -0.0927F, 0, 6.79F,
0.0821F, 0.9145F, 0.0634F, 0, 6.79F,
0.2019F, 0.1097F, 0.7483F, 0, 6.79F,
0, 0, 0, 1, 0
}));
protected void onDraw(Canvas canvas){
int sc = canvas.saveLayer(...,null,Canvas.ALL_SAVE_FLAG) ;
canvas.drawColor(0xcc1c093e) ;
mPaint.setXfermode(mXfermode) ;
canvas.drawBitmap(bitmap,x,y,mPaint) ;
mPaint.setXfermode(null) ;
canvas.restoreToCount(sc) ;
}
模擬單反相機(jī)的暗角效果浊洞,壓暗圖片周圍的顏色亮度提亮中心:
姿勢訣竅第二式:
onDraw() 最后添加
// 實(shí)例化混合模式
// 中心顏色為透明而邊緣顏色為黑色
mShaderPaint.setShader(new RadialGradient(screenW / 2, screenH / 2,
mBitmap.getHeight() * 7 / 8, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP));
// 繪制一個(gè)跟圖片大小一樣的矩形
canvas.drawRect(x, y, x + mBitmap.getWidth(), y + mBitmap.getHeight(), mShaderPaint);
姿勢二存在的問題:
- 只能是圓形的漸變牵敷,對顏色區(qū)域的把控能力不足 ;
姿勢2.1 矩陣亮相
// 根據(jù)我們源圖的大小生成暗角Bitmap
darkCornerBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
// 將該暗角Bitmap注入Canvas
Canvas canvas = new Canvas(darkCornerBitmap);
// 計(jì)算徑向漸變半徑
float radiu = canvas.getHeight() * (2F / 3F);
// 實(shí)例化Shader圖形的畫筆
mShaderPaint = new Paint();
// 設(shè)置徑向漸變法希,漸變中心當(dāng)然是圖片的中心也是屏幕中心枷餐,漸變半徑我們直接拿圖片的高度但是要稍微小一點(diǎn)
// 中心顏色為透明而邊緣顏色為黑色
RadialGradient radialGradient = new RadialGradient(screenW / 2 , screenH / 2 ,
mBitmap.getHeight() * 7 / 8, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
// 實(shí)例化一個(gè)矩陣
Matrix matrix = new Matrix();
// 設(shè)置矩陣的縮放
matrix.setScale(canvas.getWidth() / (radiu * 2F), 1.0F);
// 設(shè)置矩陣的預(yù)平移
matrix.preTranslate(((radiu * 2F) - canvas.getWidth()) / 2F, 0);
// 將該矩陣注入徑向漸變
radialGradient.setLocalMatrix(matrix);
mShaderPaint.setShader(radialGradient);
// 繪制矩形
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mShaderPaint);
把姿勢二onDraw換成
//繪制我們畫好的徑向漸變圖
canvas.drawBitmap(darkCornerBitmap, x, y, null);