三祝辣、Android繪制知識(shí)總結(jié)(畫筆篇)

Paint(畫筆)贴妻,Android中繪制界面最常見的一個(gè)類,它的設(shè)計(jì)思路其實(shí)也遵從現(xiàn)實(shí)中畫筆的定義:在畫布(Canvas)上繪制內(nèi)容的對(duì)象蝙斜。
我們通過設(shè)置Paint相關(guān)屬性名惩,就可以在畫布上繪制不同樣式的圖案。

1乍炉、常用API

函數(shù) 解釋
void setColor(int color) 設(shè)置畫筆顏色
void setStyle(Style style) 描邊效果绢片。
可選值包括FILLFILL_AND_STROKE岛琼、STROKE
void setStrokeWidth(float width) 設(shè)置畫筆寬度底循,單位是px。
只在Style為STROKEFILL_AND_STROKE時(shí)有效
void setAntiAlias(boolean aa) 抗鋸齒槐瑞,繪制不規(guī)則圖形使用熙涤,如果繪制矩形、位圖困檩,就不需要打開
void setDither(boolean dither) 抗抖動(dòng)
setStrokeMiter(float miter)
void setStrokeCap(Cap cap) 線帽風(fēng)格祠挫。
Cap.ROUND(圓形),Cap.SQUARE(方形),Cap.BUTT (無線帽)。
void setStrokeJoin(Join join) 拐角風(fēng)格悼沿。
Join.MITER(銳角),Join.ROUND(圓坏忍颉),Join.BEVEL(直線)
void setFilterBitmap(boolean filter) 雙線性濾波

注意:在Android系統(tǒng)在,顏色一般由一個(gè)int值表示:int color = (alpha<<24) | (red<<16) | (green<<8) | blue


2糟趾、文字相關(guān)API

2.1慌植、文字相關(guān)函數(shù)

函數(shù) 解釋
void setTextSize(float textSize) 設(shè)置字體大小
void setTextAlign(Align align) 設(shè)置文字對(duì)齊方式,包括LEFT义郑、CENTER蝶柿、RIGHT
void setFakeBoldText(boolean) 設(shè)置是否為粗體
void setUnderlineText(boolean) 設(shè)置下劃線
void setTextSkewX(float) 設(shè)置字體水平傾斜度,普通斜體字設(shè)為-0.25
void setStrikeThruText(boolean) 設(shè)置帶有刪除線效果
void setTextScaleX(2) 水平縮放

2.2非驮、字體相關(guān)函數(shù)

1交汤、設(shè)置字體樣式
Typeface setTypeface(Typeface typeface)
typeface取值:Typeface.SANS_SERIFTypeface.MONOSPACE劫笙、Typeface.SERIF芙扎,但對(duì)中文支持不好星岗,一般都不使用。

2纵顾、根據(jù)字體樣式獲取對(duì)應(yīng)的默認(rèn)字體
Typeface defaultFromStyle(int style)
直接通過指定字體名來加載系統(tǒng)中自帶的字體樣式伍茄,如果字體樣式不存在栋盹,則返回系統(tǒng)樣式施逾。style取值如下:
Typeface.NORMAL: 正常字體。
Typeface.BOLD: 粗體例获。
Typeface.ITALIC: 斜體汉额。
Typeface.BOLD_ITALIC: 粗斜體。

3榨汤、創(chuàng)建字體
3.1蠕搜、獲取系統(tǒng)自帶的字體
Typeface create(String familyName, int style)

3.2、獲取應(yīng)用Asset目錄下的字體
Typeface createFromAsset(AssetManager mgr, String path)

3.3收壕、從字體文件中獲得字體
Typeface createFromFile(String path)
Typeface createFromFile(File path)

2.3妓灌、文字的測量

1、文字的外接矩形
void getTextBounds(String text, int start, int end, Rect bounds)
注意蜜宪,這個(gè)矩形是根據(jù)基線位置為(0,0)得到的

2虫埂、測量文字寬度
float measureText(char[] text, int index, int count)
float measureText(String text, int start, int end)
float measureText(String text)
float measureText(CharSequence text, int start, int end)

3、文字的基線
文字的繪制位置圃验,不是由文字左上角位置所決定的掉伏,而是由文字的TextAlignbaseline所控制的:

  • 當(dāng)TextAlign為LEFT時(shí)(默認(rèn)),繪制點(diǎn)為(x=文字開始位置澳窑,y=baseline)
  • 當(dāng)TextAlign為CENTER時(shí)斧散,繪制點(diǎn)為(x=文字中心位置,y=baseline)
  • 當(dāng)TextAlign為RIGHT時(shí)摊聋,繪制點(diǎn)為(x=文字結(jié)束位置鸡捐,y=baseline)

由此可見,繪制文字的關(guān)鍵麻裁,在于找到baseline箍镜,這時(shí)就要用到Paint.getFontMetrics()函數(shù)了,該函數(shù)返回一個(gè)FontMetrics對(duì)象悲立,其中包含以下變量:

變量 含義
ascent 字體最佳繪制區(qū)域頂部到baseline的距離
top 字體最大繪制區(qū)域頂部到baseline的距離
descent 字體最佳繪制區(qū)域底部到baseline的距離
bottom 字體最大繪制區(qū)域底部到baseline的距離
leading 上一行字符的descent到下一行的ascent之間的距離

它們與baseline的位置關(guān)系如圖所示:

image.png

我們通過FontMetrics鹿寨,能夠很快的計(jì)算出baseLine注意薪夕,由于坐標(biāo)系的關(guān)系脚草,F(xiàn)ontMetrics的bottom為正數(shù),top為負(fù)數(shù)原献。


3馏慨、高級(jí)

3.1埂淮、setShadowLayer

如果需要給TextView的文字添加陰影,有兩種方式:

1写隶、xml布局中設(shè)置shadowRadius倔撞、shadowDxshadowDy慕趴、shadowColor這4個(gè)屬性
2痪蝇、調(diào)用TextView的setShadowLayer方法。

這里我們介紹第二種冕房,setShadowLayer可以在當(dāng)前圖層下方繪制一個(gè)陰影圖層躏啰,并具有指定的偏移量和顏色以及模糊半徑。

void setShadowLayer(float radius, float dx, float dy, int shadowColor)
參數(shù)含義:
radius:陰影模糊半徑
dxdy:陰影位置偏移
shadowColor:陰影顏色

注意:設(shè)置setShadowLayer后耙册,繪制Bitmap的陰影效果會(huì)有所不同(也跟系統(tǒng)版本相關(guān)):
1给僵、如果Bitmap是彩色不透明圖像,如由jpg圖片獲取的Bitmap

陰影由Bitmap模糊后加上shadowColor的alpha得到详拙。

image.png

2帝际、如果Bitmap是單色不透明圖像,如由jpg圖片獲取的Bitmap饶辙,并調(diào)用Bitmap.extractAlpha()

陰影由shadowColor模糊而來蹲诀。

image.png

3、如果Bitmap是彩色透明圖像畸悬,如由png圖片獲取的Bitmap

1侧甫、陰影不會(huì)被模糊
2、陰影由Bitmap和shadowColor的alpha得到蹋宦。

image.png

4披粟、如果Bitmap是單色透明圖像,如由png圖片獲取的Bitmap冷冗,并調(diào)用Bitmap.extractAlpha()

1守屉、陰影不會(huì)被模糊
2、陰影顏色是shadowColor蒿辙。

image.png

總結(jié):

1拇泛、如果圖片帶有透明通道,陰影將不會(huì)被模糊思灌,并受shadowColor的alpha值影響俺叭。
2、如果圖片是單色泰偿,陰影將由shadowColor決定熄守。

當(dāng)不再需要陰影時(shí),可以通過將radius設(shè)置為0,或者調(diào)用clearShadowLayer來清除陰影裕照。


3.2攒发、setMaskFilter

MaskFilter setMaskFilter(MaskFilter maskfilter)

MaskFilter有2個(gè)子類:

  • BlurMaskFilter:模糊效果
  • EmbossMaskFilter:浮雕效果

其中BlurMaskFilter構(gòu)造函數(shù)
public BlurMaskFilter(float radius, Blur style)
需要指定模糊半徑,和模糊類型:

模糊類型 含義
NORMAL 內(nèi)外都模糊
SOLID 內(nèi)部直接繪制晋南,外部模糊
OUTER 內(nèi)部不繪制惠猿,外部模糊
INNER 模糊內(nèi)部,外部不繪制
image.png

注意:使用BlurMaskFilter模糊Bitmap時(shí)负间,也有跟setShadowLayer一樣的限制偶妖,只有當(dāng)Bitmap不透明,才會(huì)有模糊效果唉擂。那如何生成一個(gè)帶透明度的純色陰影圖片呢餐屎?
可通過設(shè)置BlurMaskFilter檀葛,再調(diào)用Bitmap extractAlpha(Paint paint, int[] offsetXY)方法即可玩祟。

public class ShadowView extends View {
    private Paint mPaint = new Paint();
    private Bitmap mAlphaBitmap;

    public ShadowView(Context context) {
        super(context);
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        mPaint.setColor(Color.BLACK);
        mPaint.setTextSize(40);
//        mPaint.setShadowLayer(10, 10, 10, Color.argb(255, 255, 0, 0));
        mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.cat_dog);
        mAlphaBitmap = Bitmap.createScaledBitmap(bitmap, 400, 400, true).extractAlpha(mPaint, new int[]{10, 10});
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.drawText("青云", 140, 200, mPaint);
        canvas.drawCircle(150, 400, 50, mPaint);
        canvas.saveLayerAlpha(new RectF(400, 50, 400 + mAlphaBitmap.getWidth(), 50 + +mAlphaBitmap.getHeight()), 100);
        canvas.drawBitmap(mAlphaBitmap, 400, 50, mPaint);
        canvas.restore();
    }
}

3.3、setPathEffect

setPathEffect(PathEffect effect)

public class EffectView extends View {
    private PathEffect[] mEffect = new PathEffect[6];
    private Path mPath = new Path();
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public EffectView(Context context) {
        super(context);
        for (int i = 0; i <= 30; i++) {
            mPath.lineTo(i * 35, (float) (Math.random() * 100));
        }

        mEffect[0] = null;
        mEffect[1] = new CornerPathEffect(30);
        mEffect[2] = new DiscretePathEffect(3.0F, 5.0F);
        mEffect[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);
        Path path = new Path();
        path.addRect(0, 0, 8, 8, Path.Direction.CCW);
        mEffect[4] = new PathDashPathEffect(path, 12, 0, PathDashPathEffect.Style.ROTATE);
        mEffect[5] = new ComposePathEffect(mEffect[3], mEffect[1]);

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (PathEffect pathEffect : mEffect) {
            mPaint.setPathEffect(pathEffect);
            canvas.drawPath(mPath, mPaint);
            canvas.translate(0, 150);
        }
    }
}
image.png

3.4屿聋、setShader

Shader setShader(Shader shader)

參數(shù):Shader 著色器對(duì)象,一般使用系統(tǒng)所提供的幾個(gè)子類:
LinearGradient:線性渲染(霓虹燈文字空扎,倒影圖片)
RadialGradient:環(huán)形渲染(水波紋效果)
SweepGradient:掃描渲染(雷達(dá)掃描效果)
BitmapShader:位圖渲染
ComposeShader:組合渲染,例如LinearGradient+BitmapShader

public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)
TileMode取值如下:

TileMode取值 含義
TileMode.CLAMP 用邊緣像素來填充多余空間
TileMode.REPEAT 重復(fù)原圖像來填充多余空間
TileMode.MIRROR 使用鏡像圖像來填充多余空間

注意:填充順序?yàn)橄蓉Q向填充润讥,再橫向填充转锈,并且繪制是從左上角進(jìn)行繪制,與畫筆位置無關(guān)楚殿。
所以這會(huì)照成一些問題撮慨,如:
1、單個(gè)圖像不能充滿整個(gè)屏幕
2脆粥、單個(gè)圖像不能在控件中部位置完整顯示
解決方案為:Shader.setLocalMatrix


3.5砌溺、setColorFilter

ColorFilter setColorFilter(ColorFilter filter)

設(shè)置顏色過濾,一般使用ColorFilter的三個(gè)子類
LightingColorFilter:光照效果
PorterDuffColorFilter:指定一個(gè)顏色和一種PorterDuff.Mode與繪制對(duì)象進(jìn)行組合
ColorMatrixColorFilter:使用一個(gè)ColorMatrix來對(duì)顏色進(jìn)行處理
    ColorMatrix類
        ColorMatrix.setScale //色度調(diào)節(jié)
        ColorMatrix.setSaturation //飽和度調(diào)節(jié)变隔,0-無色彩规伐,1-默認(rèn)效果,>1飽和度加強(qiáng)
        ColorMatrix.setRotate //色調(diào)調(diào)節(jié)

常見效果:

  • 平移運(yùn)算---加法
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        1, 0, 0, 0, 0,
        0, 1, 0, 0, 100,
        0, 0, 1, 0, 0,
        0, 0, 0, 1, 0,
});
  • 反相效果 -- 底片效果
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        -1, 0, 0, 0, 255,
        0, -1, 0, 0, 255,
        0, 0, -1, 0, 255,
        0, 0, 0, 1, 0,
});
  • 縮放運(yùn)算---乘法 -- 顏色增強(qiáng)
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        1.2f, 0, 0, 0, 0,
        0, 1.2f, 0, 0, 0,
        0, 0, 1.2f, 0, 0,
        0, 0, 0, 1.2f, 0,
});
  • 黑白照片
    將三通道變?yōu)閱瓮ǖ赖幕叶饶J?br> 原理:只要把R G B 三通道的色彩信息設(shè)置成一樣匣缘,那么圖像就會(huì)變成灰色猖闪,同時(shí)為了保證圖像亮度不變,同一個(gè)通道里的R+G+B =1
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        0.213f, 0.715f, 0.072f, 0, 0,
        0.213f, 0.715f, 0.072f, 0, 0,
        0.213f, 0.715f, 0.072f, 0, 0,
        0, 0, 0, 1, 0,
});
  • 發(fā)色效果---(比如紅色和綠色交換)
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        1, 0, 0, 0, 0,
        0, 0, 1, 0, 0,
        0, 1, 0, 0, 0,
        0, 0, 0, 0.5F, 0,
});
  • 復(fù)古效果
ColorMatrix colorMartrix = new ColorMatrix(new float[]{
        1 / 2f, 1 / 2f, 1 / 2f, 0, 0,
        1 / 3f, 1 / 3f, 1 / 3f, 0, 0,
        1 / 4f, 1 / 4f, 1 / 4f, 0, 0,
        0, 0, 0, 1, 0,
});

3.6肌厨、setXfermode

混合模式是Paint繪圖中最難的部分培慌,它能夠?qū)蓮垐D片無縫結(jié)合,實(shí)現(xiàn)類似Photoshop中的兩張圖片融合效果柑爸。
Xfermode setXfermode(Xfermode xfermode)
Xfermode是一個(gè)空類吵护,PorterDuffXfermode是其唯一的子類。
在介紹Xfermode之前,我們先介紹一下PorterDuff.Mode離屏渲染相關(guān)知識(shí)何址。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末里逆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子用爪,更是在濱河造成了極大的恐慌原押,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偎血,死亡現(xiàn)場離奇詭異诸衔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)颇玷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門笨农,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人帖渠,你說我怎么就攤上這事谒亦。” “怎么了空郊?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵份招,是天一觀的道長。 經(jīng)常有香客問我狞甚,道長锁摔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任哼审,我火速辦了婚禮谐腰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涩盾。我一直安慰自己十气,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布旁赊。 她就那樣靜靜地躺著桦踊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪终畅。 梳的紋絲不亂的頭發(fā)上籍胯,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音离福,去河邊找鬼杖狼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妖爷,可吹牛的內(nèi)容都是我干的蝶涩。 我是一名探鬼主播理朋,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼绿聘!你這毒婦竟也來了嗽上?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤熄攘,失蹤者是張志新(化名)和其女友劉穎兽愤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挪圾,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浅萧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哲思。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洼畅。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖棚赔,靈堂內(nèi)的尸體忽然破棺而出帝簇,到底是詐尸還是另有隱情,我是刑警寧澤忆嗜,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布己儒,位于F島的核電站,受9級(jí)特大地震影響捆毫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冲甘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一绩卤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧江醇,春花似錦濒憋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至条辟,卻和暖如春黔夭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背羽嫡。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工本姥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杭棵。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓婚惫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子先舷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 常用方法 構(gòu)造方法 Paint mPaint = new Paint(); 重置畫筆 mPaint.reset()...
    cain07閱讀 473評(píng)論 0 7
  • 其實(shí)這邊并不需要你記住太多艰管,能有知道有這樣的作用,讓后不會(huì)使用的時(shí)候當(dāng)工具來查看就看蒋川。主要是需要能靈活運(yùn)用這些蛙婴。下...
    帝王鯊kingcp閱讀 689評(píng)論 0 2
  • 常用方法 構(gòu)造方法 Paint mPaint = new Paint(); 重置畫筆 mPaint.reset()...
    孤獨(dú)的根號(hào)十二閱讀 11,317評(píng)論 0 17
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭尔破,有人歡樂有人憂愁街图,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,523評(píng)論 28 53
  • 信任包括信任自己和信任他人 很多時(shí)候懒构,很多事情餐济,失敗、遺憾胆剧、錯(cuò)過絮姆,源于不自信,不信任他人 覺得自己做不成秩霍,別人做不...
    吳氵晃閱讀 6,181評(píng)論 4 8