現實生活中作畫,有兩樣東西必不可少:筆、紙,Android中圖形繪制類似于此.
在Android中:
Paint類就是我們的“畫筆”,為繪圖定義各種參數:顏色、文本樣式、圖形樣式等等.
Canvas類就是我們的“畫布”,Canvas類中提供了若干方法用于繪制各種圖案:點、線、矩形、圓等等.
掌握Graphics繪圖是自定義組件的基礎,Android給了我們一支筆(Paint)和一張紙(Canvas),畫出什么樣的圖形取決于我們的想象力以及對Graphics繪圖的掌握程度.
一、Paint類
Paint類就是畫筆,用來設置繪圖時的參數,比如:筆的顏色、筆的粗細等等.
使用方法很簡單,首先定義一個畫筆對象:
Paint mPaint = new Paint();
然后就可以調用Paint以set開頭的相關方法為畫筆設置各種參數了:
mPaint.set......
最后,在畫布Canvas調用相關繪圖方法的時候把畫筆對象Paint傳進去就可以了:
canvas.draw......(其它參數.....,mPaint);
這里先簡單介紹畫筆的幾個方法,后面會詳細介紹畫筆Paint.
1、畫筆顏色設置
畫筆肯定有顏色了,Paint設置顏色的方法有下面3個,我們一般使用的是第1個
public void setColor(int color) 設置顏色值
public void setAlpha(int a) 設置透明度
public void setARGB(int a, int r, int g, int b) 指定透明度、紅、綠、藍定義一種顏色
2、畫筆填充樣式設置
public void setStyle(Style style)
設置畫筆填充樣式,可選值:
Paint.Style.FILL 填充內部(默認值)
Paint.Style.STROKE 僅描邊
Paint.Style.FILL_AND_STROKE 填充內部和描邊
上圖是調用Canvas畫了一個正方形在Paint三種填充樣式下的效果,FILL就是內部填充滿畫筆的顏色,STROKE就是圖形是空心的,在外層描邊,所以STROKE看著比FILL大一點,FILL_AND_STROKE就是兩者的綜合.
3、畫筆寬度、抗鋸齒功能
public void setStrokeWidth(float width) 設置畫筆寬度
當畫筆填充樣式為STROKE 、FILL_AND_STROKE 的時候,我們可以設置畫筆的寬度,畫筆寬度越大,描的邊就越“厚”.
public void setAntiAlias(boolean aa)
aa為true時開啟抗鋸齒功能
我們畫一條直線,細看是直的,但是仔細看會發現直線上有很多鋸齒,就像電鋸一樣,這個方法可以讓繪圖過程中的線條更加平滑.
4、文本樣式設置
Canvas是可以繪制文字的,文字的顏色就是Paint設置的顏色,Paint還可以為文字設置下面這些樣式:
public void setTextSize(float textSize)
設置文本字體大小,單位px
public void setTextAlign(Align align)
設置文本對齊方式,可選值:Paint.Align.LEFT、Paint.Align.CENTER、Paint.Align.RIGHT
繪制文本時會有個起始點坐標,三個值分別代表:在起始坐標的左邊繪制文本、以起始坐標為中心繪制文本、在起始坐標的右邊繪制文本
public void setTextScaleX(float scaleX)
將文本沿X軸水平縮放,默認值為1,大于1時會沿X軸水平放大文本,小于1會沿X軸水平縮放文本
public void setTextSkewX(float skewX)
設置文本傾斜程度,范圍:-1~1,正負表示傾斜的方向,默認0不傾斜
public void setUnderlineText(boolean underlineText)
給文本添加下劃線,true添加下劃線
public void setFakeBoldText(boolean fakeBoldText)
文本粗體設置,true表示設置為粗體
public void setStrikeThruText(boolean strikeThruText)
文本添加刪除線,true表示添加刪除線
5、copy畫筆、重置畫筆
public void set(Paint src)
為當前畫筆設置一個畫筆
在繪圖時,有時我們會用到不止一種畫筆,如果有個畫筆的屬性都設置好了,另外一個畫筆也需要這些屬性,就可以直接copy過來
public void reset()
重置畫筆,恢復初始狀態
二、Canvas類
Canvas類提供了大量以draw...開頭的方法用于繪圖.
一般在繪圖前,先創建Paint對象,定義繪制的顏色、樣式等參數. 因為Paint對象可以重置(reset),所以除非有必要,Paint對象創建一個就可以了,然后再調用Canvas的繪圖方法.
Canvas繪圖方法主要有下面幾種類型:
顏色
點
線
矩形
圓
路徑
文字
位圖
Canvas操作
1、前置
在講繪圖方法前,我們先自定義一個簡單的XView繼承自View,不然光介紹API不是很好理解.
public class XView extends View {
private Paint mPaint;
public XView(Context context) {
this(context, null);
}
public XView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();//初始化畫筆
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
gogogo(canvas);
}
/**
* 后面所有測試代碼都在gogogo中
*/
private void gogogo(Canvas canvas){
...
}
}
然后在布局文件中使用:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.fgq.demo.XView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
自定義的View在布局文件中寫法:完整包名+類名
2、繪制顏色
public void drawRGB(int r, int g, int b)
public void drawARGB(int a, int r, int g, int b)
public void drawColor(int color)
這里繪制的是整個畫布的顏色
測試:
private void gogogo(Canvas canvas){
canvas.drawColor(Color.GRAY);
}
3、繪制點
雖然是點,但并不表面它很小,點的大小取決于畫筆寬度,也就是Paint.setStrokeWidth(...)參數的大小.
關于點,請看Point類、PointF類.
public void drawPoint(float x, float y, Paint paint)
在(x,y)處繪制一個點
public void drawPoints(float[] pts, Paint paint)
連續繪制多個點:pts是一個數組,從下標0開始,每2個數組元素確定一個點,數組長度必須是2的倍數
public void drawPoints(float[] pts, int offset, int count,Paint paint)
連續繪制多個點:pts是一個數組,從下標offset開始取數組元素,每2個數組元素確定一個點,一共取count個元素
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(20f);
mPaint.setColor(Color.BLUE);
canvas.drawPoint(50, 50, mPaint);//點(50,50)
mPaint.setStrokeWidth(30f);
mPaint.setColor(Color.RED);
canvas.drawPoints(new float[]{50, 100, 110, 100, 188, 100}, mPaint);//點(50,100)、(110,100)、(188,100)
mPaint.setColor(Color.BLACK);
canvas.drawPoints(new float[]{50, 150, 110, 150, 188, 150}, 2, 4, mPaint);//點(110,150)、(188,150)
4、繪制線段
兩個點確定一條線段,所以,繪制一條線段時需要兩個點的坐標,線段的粗細由畫筆寬度決定
public void drawLine(float startX,float startY,float stopX,float stopY,Paint paint)
在(startX,startY)和(stopX,stopY) 兩個點之間繪制一條線段
public void drawLines(float[] pts, Paint paint)
繪制多條線段:pts是一個數組,從下標0開始,每4個數組元素確定一條線段,數組長度必須是4的倍數
public void drawLines(float[] pts, int offset, int count,Paint paint)
繪制多條線段:pts是一個數組,從下標offset開始取數組元素,每4個數組元素確定一條線段,一共取count個元素,數組長度必須是4的倍數
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);//圓形筆觸
mPaint.setStrokeWidth(20f);
mPaint.setColor(Color.BLUE);
canvas.drawLine(50, 50, 500, 50, mPaint);//點(50,50)到(500,50)的線段
mPaint.setColor(Color.RED);
canvas.drawLines(new float[]{50, 50, 50, 500, 500, 50, 500, 500}, mPaint);//點(50,50)到(50,500)的線段、點(500,50)到(500,500)的線段
mPaint.setColor(Color.BLACK);
canvas.drawLines(new float[]{50, 50, 50, 500, 500, 500, 0, 0}, 2, 4, mPaint);//點(50,50)到(500,500)的線段
}
5、繪制矩形
矩形分為:直角矩形、圓角矩形.(正方形也是矩形的一種)
關于矩形,請看Rect類、RectF類.
直角矩形:
public void drawRect(float left, float top, float right, float bottom, Paint paint)
public void drawRect(Rect r, Paint paint)
public void drawRect(RectF rect, Paint paint)
這三個重載方法繪制矩形的本質是完全一樣的,使用哪一個隨意
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(20f);
mPaint.setColor(Color.BLUE);
canvas.drawRect(50, 50, 200, 200, mPaint);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.RED);
canvas.drawRect(new Rect(50,250,200,400),mPaint);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(Color.BLACK);
canvas.drawRect(new RectF(50f,450f,200f,600f),mPaint);
}
圓角矩形:
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint)
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,Paint paint)
相對于直角矩形,圓角矩形多了兩個參數:rx、ry
這兩個參數用來指定4個角的弧度,分別是圓角處的水平半徑、豎直半徑
若rx=ry,則4個拐角是半徑為rx的圓的1/4圓弧,
若rx≠ry,則4個拐角是長半軸、短半軸為rx、ry的橢圓的1/4圓弧.
這二個重載方法繪制矩形的本質是完全一樣的,不同的是第二個需要在>=5.0(API 21)的版本使用
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
canvas.drawRoundRect(50, 50, 600, 600, 20, 40, mPaint);
mPaint.setColor(Color.RED);
canvas.drawRoundRect(new RectF(100, 100, 400, 400), 30, 30, mPaint);
}
6、繪制圓
我把橢圓、圓、弧、扇形統一歸類到“圓”中.
(1)橢圓
橢圓的大小由它的外切矩形決定.
public void drawOval(RectF oval, Paint paint)
public void drawOval(float left, float top, float right, float bottom, Paint paint)
這兩個重載方法本質一樣,都是通過定義橢圓的外切矩形來繪制橢圓
(第二個重載方法需要在>=5.0(API 21)的版本使用)
(2)圓
圓的大小由圓心、半徑決定.
public void drawCircle(float cx, float cy, float radius, Paint paint)
圓心:(cx,cy) 半徑:radius
(3)弧、扇形
弧和扇形相似,都是橢圓上一部分,而橢圓又是由它的外切矩形決定
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)
public void drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter,Paint paint)
startAngle:開始角度
sweepAngle:弧線、扇形所占角度,正數順時針,負數逆時針
useCenter:是否使用中心點,true表示扇形、false表示弧線
(第二個重載方法需要在>=5.0(API 21)的版本使用)
當矩形長、寬一樣時,就是正方形,橢圓就變成圓,弧線、扇形就是圓上一部分了
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
RectF rectF = new RectF(50, 50, 600, 400);
canvas.drawOval(rectF, mPaint);//橢圓
mPaint.setColor(Color.RED);
canvas.drawCircle(325, 225, 175, mPaint);//圓
mPaint.setColor(Color.YELLOW);
canvas.drawArc(rectF, 90, 90, false, mPaint);//弧
mPaint.setStyle(Paint.Style.FILL);
canvas.drawArc(rectF, 180, 90, false, mPaint);//弧
canvas.drawArc(rectF, 30, 30, true, mPaint);//扇形
canvas.drawArc(rectF, -30, 30, true, mPaint);//扇形
}
7、繪制文字
(1)從指定位置開始繪制文字:
public void drawText(String text, float x, float y, Paint paint)
public void drawText(char[] text, int index, int count, float x, float y,Paint paint)
public void drawText(String text, int start, int end, float x, float y,Paint paint)
public void drawText(CharSequence text, int start, int end, float x, float y,
Paint paint)
文字內容:text
部分內容:index、count------從下標index開始取,一共取count個數組元素;start、end------從字符串索引start到end處的部分字符串
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLUE);
mPaint.setTextSize(40);//設置字體大小
String text = "隨風飄揚的Smile";
canvas.drawText(text, 50, 50, mPaint);//繪制文字
mPaint.setTextSkewX(-0.5f);//向左傾斜
canvas.drawText(text, 50, 100, mPaint);
mPaint.setTextSkewX(0.5f);//向右傾斜
canvas.drawText(text, 50, 150, mPaint);
mPaint.setUnderlineText(true);//下劃線
canvas.drawText(text.toCharArray(), 1, 2, 50, 200, mPaint);
mPaint.setFakeBoldText(true);//粗體
mPaint.setStrikeThruText(true);//刪除線
canvas.drawText(text, 2, text.length() - 1, 50, 250, mPaint);
mPaint.setTextScaleX(1.5f);//水平放大文本
canvas.drawText(text, 50, 300, mPaint);
}
(2)沿著Path路徑繪制文字:
關于Path,請看Path類基本操作.
public void drawTextOnPath(String text, Path path, float hOffset,
float vOffset, Paint paint)
public void drawTextOnPath(char[] text, int index, int count,Path path,
float hOffset, float vOffset, Paint paint)
hOffset:文字與路徑起始點的水平偏移距離
vOffset:文字與路徑豎直方向偏移量,>0往Path下方偏移,<0往Path上方偏移
同樣支持截取部分內容:從index處取元素,一共取count個元素
測試:
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.BLUE);
mPaint.setTextSize(30);
String text = "隨風飄揚的Smile";
Path path = new Path();
path.moveTo(50, 200);
path.lineTo(666, 666);//線段
//沿著Path繪制文字
canvas.drawTextOnPath(text+"1", path, 0, 0, mPaint);
canvas.drawTextOnPath(text+"2", path, 0, -30, mPaint);
canvas.drawTextOnPath(text+"3", path, 300, 0, mPaint);
canvas.drawTextOnPath(text+"4", path, 0, 30, mPaint);
canvas.drawTextOnPath(text+"5", path, 300, 30, mPaint);
Path path2 = new Path();
path2.addCircle(300,300,200, Path.Direction.CCW);//逆向圓,文字沿著逆向
canvas.drawTextOnPath(text, path2, 0, 0, mPaint);//沿著Path繪制文字
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, mPaint);//繪制Path---線段
canvas.drawPath(path2, mPaint);//繪制Path---圓
}
(3)指定文字位置:
public void drawPosText(String text, float[] pos,Paint paint)
public void drawPosText(char[] text, int index, int count,float[] pos,Paint paint)
text:文子內容
pos:每個文字的坐標位置,一個坐標需要2個參數,所以數組pos長度必須是2的倍數
index:第一個文字索引
count:一共繪制count個文字
測試
private void gogogo(Canvas canvas) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true); //使用抗鋸齒功能
mPaint.setTextSize(50);
float[] textPos = new float[]{10, 50,
20, 100,
30, 150,
40, 200,
50, 250,
60, 300,
};
canvas.drawPosText("隨風飄揚的笑", textPos, mPaint);
}
8、繪制位圖
public void drawBitmap(Bitmap bitmap, float left, float top,Paint paint)
將bitmap繪制在畫布上,同時指定位圖相左上角位置(left,top),bitmap大小與原圖一樣,不進行縮放
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst,Paint paint)
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst,Paint paint)
從bitmap中摳出大小為src的矩形區域繪制到畫布dst矩形處,bitmap會縮放適應src區域,所以src與dst的大小與比例關系影響最終繪制效果
若src為null,就將原bitmap繪制到dst處,bitmap會縮放適應src區域
測試
private void gogogo(Canvas canvas) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
canvas.drawBitmap(bitmap, 50, 50, mPaint);
canvas.drawBitmap(bitmap, new Rect(0, 0, 30, 30), new Rect(100, 100, 400, 400), mPaint);
}