1.setStyle(Paint.Style style)
設(shè)置畫筆樣式,取值有
Paint.Style.FILL :填充內(nèi)部
Paint.Style.FILL_AND_STROKE :填充內(nèi)部和描邊
Paint.Style.STROKE :僅描邊
代碼實例:
public class PaintViewBasic extends View {
private Paint mPaint;
public PaintViewBasic(Context context) {
super(context);
mPaint = new Paint();
}
public PaintViewBasic(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawStyle(canvas);
}
private void drawStyle( Canvas canvas ) {
mPaint.setColor(Color.RED);//設(shè)置畫筆的顏色
mPaint.setTextSize(60);//設(shè)置文字大小
mPaint.setStrokeWidth(5);//設(shè)置畫筆的寬度
mPaint.setAntiAlias(true);//設(shè)置抗鋸齒功能 true表示抗鋸齒 false則表示不需要這功能
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(200,200,160,mPaint);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(200,600,160,mPaint);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(200,1000,160,mPaint);
}
}

2.setStrokeCap(Paint.Cap cap)
設(shè)置線冒樣式,取值有
Paint.Cap.BUTT(無線冒)
Paint.Cap.ROUND(圓形線冒)
Paint.Cap.SQUARE(方形線冒)
注意:冒多出來的那塊區(qū)域就是線帽!就相當(dāng)于給原來的直線加上一個帽子一樣,所以叫線帽
private void drawStrokeCap(Canvas canvas) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(200);
paint.setColor(Color.parseColor("#00ff00"));
paint.setStrokeCap(Paint.Cap.BUTT); // 線帽,即畫的線條兩端是否帶有圓角,butt,無圓角
canvas.drawLine(200, 200, 500, 200, paint);
paint.setColor(Color.parseColor("#ff0000"));
paint.setStrokeCap(Paint.Cap.ROUND); // 線帽,即畫的線條兩端是否帶有圓角,ROUND,圓角
canvas.drawLine(200, 500, 500, 500, paint);
paint.setColor(Color.parseColor("#0000ff"));
paint.setStrokeCap(Paint.Cap.SQUARE); // 線帽,即畫的線條兩端是否帶有圓角,SQUARE,矩形
canvas.drawLine(200, 800, 500, 800, paint);
}

3.setStrokeJoin(Paint.Join join)
設(shè)置線段連接處樣式,取值有:
Paint.Join.MITER(結(jié)合處為銳角)
Paint.Join.Round (結(jié)合處為圓弧)
Paint.Join.BEVEL (結(jié)合處為直線)
private void drawStrokeJoin( Canvas canvas ) {
Paint paint = new Paint();
paint.setAntiAlias( true );
paint.setStrokeWidth( 80 );
paint.setStyle(Paint.Style.STROKE ); // 默認(rèn)是填充 Paint.Style.FILL
paint.setColor( Color.parseColor("#0000ff") );
Path path = new Path();
path.moveTo(100, 100);
path.lineTo(400, 100);
path.lineTo(100, 300);
paint.setStrokeJoin(Paint.Join.MITER);
canvas.drawPath(path, paint);
path.moveTo(100, 500);
path.lineTo(400, 500);
path.lineTo(100, 700);
paint.setStrokeJoin(Paint.Join.ROUND);
canvas.drawPath(path, paint);
path.moveTo(100, 900);
path.lineTo(400, 900);
path.lineTo(100, 1100);
paint.setStrokeJoin(Paint.Join.BEVEL);
canvas.drawPath(path, paint);
}
}

4.setPathEffect(PathEffect effect)
設(shè)置繪制路徑的效果,如點畫線等
CornerPathEffect:
這個類的作用就是將Path的各個連接線段之間的夾角用一種更平滑的方式連接,類似于圓弧與切線的效果。
一般的,通過CornerPathEffect(float radius)指定一個具體的圓弧半徑來實例化一個CornerPathEffect。
DashPathEffect:
這個類的作用就是將Path的線段虛線化。
構(gòu)造函數(shù)為DashPathEffect(float[] intervals, float offset),其中intervals為虛線的ON和OFF數(shù)組,該數(shù)組的length必須大于等于2,phase為繪制時的偏移量。
DiscretePathEffect:
這個類的作用是打散Path的線段,使得在原來路徑的基礎(chǔ)上發(fā)生打散效果。
一般的,通過構(gòu)造DiscretePathEffect(float segmentLength,float deviation)來構(gòu)造一個實例,其中,segmentLength指定最大的段長,deviation指定偏離量。
PathDashPathEffect:
這個類的作用是使用Path圖形來填充當(dāng)前的路徑,其構(gòu)造函數(shù)為PathDashPathEffect (Path shape, float advance, float phase,PathDashPathEffect.Stylestyle)。
shape則是指填充圖形,advance指每個圖形間的間距,phase為繪制時的偏移量,style為該類自由的枚舉值,有三種情況:Style.ROTATE、Style.MORPH和
Style.TRANSLATE。其中ROTATE的情況下,線段連接處的圖形轉(zhuǎn)換以旋轉(zhuǎn)到與下一段移動方向相一致的角度進(jìn)行轉(zhuǎn)轉(zhuǎn),MORPH時圖形會以發(fā)生拉伸或壓縮等變形的情況與下一段相連接,TRANSLATE時,圖形會以位置平移的方式與下一段相連接。
ComposePathEffect:
組合效果,這個類需要兩個PathEffect參數(shù)來構(gòu)造一個實例,ComposePathEffect (PathEffect outerpe,PathEffect innerpe),表現(xiàn)時,會首先將innerpe表現(xiàn)出來,然后再在innerpe的基礎(chǔ)上去增加outerpe的效果。
SumPathEffect:
疊加效果,這個類也需要兩個PathEffect作為參數(shù)SumPathEffect(PathEffect first,PathEffect second),但與ComposePathEffect不同的是,在表現(xiàn)時,會分別對兩個參數(shù)的效果各自獨立進(jìn)行表現(xiàn),然后將兩個效果簡單的重疊在一起顯示出來。
關(guān)于參數(shù)phase
在存在phase參數(shù)的兩個類里,如果phase參數(shù)的值不停發(fā)生改變,那么所繪制的圖形也會隨著偏移量而不斷的發(fā)生變動,這個時候,看起來這條線就像動起來了一樣。
private float phase;
private PathEffect[] effects;
private int[] colors;
private void drawPathEffect(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4);
// 創(chuàng)建,并初始化Path
Path path = new Path();
path.moveTo(0, 0);
for (int i = 1; i <= 35; i++) {
// 生成15個點,隨機(jī)生成它們的坐標(biāo),并將它們連成一條Path
path.lineTo(i * 20, (float) Math.random() * 60);
}
// 初始化七個顏色
colors = new int[]{Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED,
Color.GRAY};
// 將背景填充成白色
canvas.drawColor(Color.WHITE);
effects = new PathEffect[7];
// -------下面開始初始化7中路徑的效果
// 使用路徑效果
effects[0] = null;
// 使用CornerPathEffect路徑效果
effects[1] = new CornerPathEffect(10);
// 初始化DiscretePathEffect
effects[2] = new DiscretePathEffect(3.0f, 5.0f);
// 初始化DashPathEffect
effects[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, phase);
// 初始化PathDashPathEffect
Path p = new Path();
p.addRect(0, 0, 8, 8, Path.Direction.CCW);
effects[4] = new PathDashPathEffect(p, 12, phase, PathDashPathEffect.Style.ROTATE);
// 初始化PathDashPathEffect
effects[5] = new ComposePathEffect(effects[2], effects[4]);
effects[6] = new SumPathEffect(effects[4], effects[3]);
// 將畫布移到8,8處開始繪制
canvas.translate(8, 8);
// 依次使用7中不同路徑效果,7種不同的顏色來繪制路徑
for (int i = 0; i < effects.length; i++) {
mPaint.setPathEffect(effects[i]);
mPaint.setColor(colors[i]);
canvas.drawPath(path, mPaint);
canvas.translate(0, 200);
}
// 改變phase值,形成動畫效果
phase += 1;
invalidate();
}

5.setShadowLayer(float radius, float dx, float dy, int shadowColor)
陰影制作:包括各種形狀(矩形,圓形等等),以及文字等等都能設(shè)置陰影。
private void drawShadowLayer(Canvas canvas) {
// 建立Paint 物件
Paint paint1 = new Paint();
paint1.setTextSize(100);
// 設(shè)定顏色
paint1.setColor(Color.BLACK);
// 設(shè)定陰影(柔邊, X 軸位移, Y 軸位移, 陰影顏色)
paint1.setShadowLayer(10, 5, 5, Color.GRAY);
// 實心矩形& 其陰影
canvas.drawText("我愛你", 20,100,paint1);
Paint paint2 = new Paint();
paint2.setTextSize(100);
paint2.setColor(Color.GREEN);
paint2.setShadowLayer(10, 6, 6, Color.GRAY);
canvas.drawText("你真傻", 20,200,paint2);
//cx和cy為圓點的坐標(biāo)
int radius = 80;
int offest = 40;
int startX = radius + offest;
int startY = radius + offest + 200;
Paint paint3 = new Paint();
//如果不關(guān)閉硬件加速,setShadowLayer無效
setLayerType(LAYER_TYPE_SOFTWARE, null);
paint3.setShadowLayer(20, -20, 10, Color.DKGRAY);
canvas.drawCircle(startX, startY, radius, paint3);
paint3.setStyle(Paint.Style.STROKE);
paint3.setStrokeWidth(5);
canvas.drawCircle(startX + radius * 2 + offest, startY, radius, paint3);
}

6.setXfermode(Xfermode xfermode)
Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為圖像混合模式,因為所謂的“過渡”其實就是圖像混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的。查看API文檔發(fā)現(xiàn)其果然有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,這三個子類實現(xiàn)的功能要比setColorFilter的三個子類復(fù)雜得多。
由于AvoidXfermode, PixelXorXfermode都已經(jīng)被標(biāo)注為過時了,所以這次主要研究的是仍然在使用的PorterDuffXfermode:
PorterDuffXfermode
該類同樣有且只有一個含參的構(gòu)造方法PorterDuffXfermode(PorterDuff.Mode mode),雖說構(gòu)造方法的簽名列表里只有一個PorterDuff.Mode的參數(shù),但是它可以實現(xiàn)很多酷斃的圖形效果?。《鳳orterDuffXfermode就是圖形混合模式的意思,其概念最早來自于SIGGRAPH的Tomas Proter和Tom Duff,混合圖形的概念極大地推動了圖形圖像學(xué)的發(fā)展,延伸到計算機(jī)圖形圖像學(xué)像Adobe和AutoDesk公司著名的多款設(shè)計軟件都可以說一定程度上受到影響,而我們PorterDuffXfermode的名字也來源于這倆人的人名組合PorterDuff,那PorterDuffXfermode能做些什么呢?我們先來看一張API DEMO里的圖片:

這張圖片從一定程度上形象地說明了圖形混合的作用,兩個圖形一圓一方通過一定的計算產(chǎn)生不同的組合效果,在API中Android為我們提供了18種(比上圖多了兩種ADD和OVERLAY)模式:
ADD:飽和相加,對圖像飽和度進(jìn)行相加,不常用
CLEAR:清除圖像
DARKEN:變暗,較深的顏色覆蓋較淺的顏色,若兩者深淺程度相同則混合
DST:只顯示目標(biāo)圖像
DST_ATOP:在源圖像和目標(biāo)圖像相交的地方繪制【目標(biāo)圖像】,在不相交的地方繪制【源圖像】,相交處的效果受到源圖像和目標(biāo)圖像alpha的影響
DST_IN:只在源圖像和目標(biāo)圖像相交的地方繪制【目標(biāo)圖像】,繪制效果受到源圖像對應(yīng)地方透明度影響
DST_OUT:只在源圖像和目標(biāo)圖像不相交的地方繪制【目標(biāo)圖像】,在相交的地方根據(jù)源圖像的alpha進(jìn)行過濾,源圖像完全不透明則完全過濾,完全透明則不過濾
DST_OVER:將目標(biāo)圖像放在源圖像上方
LIGHTEN:變亮,與DARKEN相反,DARKEN和LIGHTEN生成的圖像結(jié)果與Android對顏色值深淺的定義有關(guān)
MULTIPLY:正片疊底,源圖像素顏色值乘以目標(biāo)圖像素顏色值除以255得到混合后圖像像素顏色值
OVERLAY:疊加
SCREEN:濾色,色調(diào)均和,保留兩個圖層中較白的部分,較暗的部分被遮蓋
SRC:只顯示源圖像
SRC_ATOP:在源圖像和目標(biāo)圖像相交的地方繪制【源圖像】,在不相交的地方繪制【目標(biāo)圖像】,相交處的效果受到源圖像和目標(biāo)圖像alpha的影響
SRC_IN:只在源圖像和目標(biāo)圖像相交的地方繪制【源圖像】
SRC_OUT:只在源圖像和目標(biāo)圖像不相交的地方繪制【源圖像】,相交的地方根據(jù)目標(biāo)圖像的對應(yīng)地方的alpha進(jìn)行過濾,目標(biāo)圖像完全不透明則完全過濾,完全透明則不過濾
SRC_OVER:將源圖像放在目標(biāo)圖像上方
XOR:在源圖像和目標(biāo)圖像相交的地方之外繪制它們,在相交的地方受到對應(yīng)alpha和色值影響,如果完全不透明則相交處完全不繪制
public class PorterDuffView extends View {
Paint mPaint;
Context mContext;
int BlueColor;
int PinkColor;
int mWith;
int mHeight;
public PorterDuffView(Context context) {
super(context);
init(context);
}
public PorterDuffView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PorterDuffView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mHeight = getMeasuredHeight();
mWith = getMeasuredWidth();
}
private void init(Context context) {
mContext = context;
BlueColor = ContextCompat.getColor(mContext, R.color.colorPrimary);
PinkColor = ContextCompat.getColor(mContext, R.color.colorAccent);
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
}
private Bitmap drawRectBm(){
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(BlueColor);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
Bitmap bm = Bitmap.createBitmap(200,200, Bitmap.Config.ARGB_8888);
Canvas cavas = new Canvas(bm);
cavas.drawRect(new RectF(0,0,70,70),paint);
return bm;
}
private Bitmap drawCircleBm(){
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(PinkColor);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
Bitmap bm = Bitmap.createBitmap(200,200, Bitmap.Config.ARGB_8888);
Canvas cavas = new Canvas(bm);
cavas.drawCircle(70,70,35,paint);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
mPaint.setFilterBitmap(false);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(20);
RectF recf = new RectF(20,20,60,60);
mPaint.setColor(BlueColor);
canvas.drawRect(recf,mPaint);
mPaint.setColor(PinkColor);
canvas.drawCircle(100,40,20,mPaint);
@SuppressLint("WrongConstant") int sc = canvas.saveLayer(0, 0,mWith,mHeight, null, Canvas.MATRIX_SAVE_FLAG |
Canvas.CLIP_SAVE_FLAG |
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
int y = 180;
int x = 50;
for(PorterDuff.Mode mode : PorterDuff.Mode.values()){
if(y >= 900){
y = 180;
x += 200;
}
mPaint.setXfermode(null);
canvas.drawText(mode.name(),x + 100,y,mPaint);
canvas.drawBitmap(drawRectBm(),x,y,mPaint);
mPaint.setXfermode(new PorterDuffXfermode(mode));
canvas.drawBitmap(drawCircleBm(),x,y,mPaint);
y += 120;
}
mPaint.setXfermode(null);
// 還原畫布
canvas.restoreToCount(sc);
}
}
