編輯:關於Android編程
canvas是一種抽象概念,是2D圖形系統中的重要部分,canvas一系列函數最終都是android 2D圖形庫Skia的一些列封裝,對應在SKCanvas.cpp。canvas在系統中的位置如下圖所示
可以將canvas看成一個透明的圖層,使用canvas之後會產生一個透明圖層,然後在這個新圖層上畫圖,畫完之後覆蓋在屏幕上顯示,疊加。
比較經典的例子就是
` protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//構造一個矩形
Rect rect1 = new Rect(0, 0, 400, 220);
//在平移畫布前用綠色畫下邊框
canvas.drawRect(rect1, paint_green);
//平移畫布後,再用紅色邊框重新畫下這個矩形
canvas.translate(100, 100);
canvas.drawRect(rect1, paint_red);
}`
我們首先畫了一個綠色矩形框,然後將canvas平移了,接著畫了一個紅色的矩形框,結果如下
這裡我們會發現,平移了canvas之後綠色矩形框沒發生變化!,拉近鏡頭我們仔細看看究竟發生了什麼,如何印證canvas每次會產生一個透明圖層?
調用canvas.drawRect(rect1, paint_green);時,產生一個Canvas透明圖層,由於當時還沒有對坐標系平移,所以坐標原點是(0,0);再在系統在Canvas上畫好之後,覆蓋到屏幕上顯示出來,過程如下圖(圖片來自網絡,鏈接在文後):
然後再第二次調用canvas.drawRect(rect1, paint_red);時,又會重新產生一個全新的Canvas畫布,此時由於使用tranlate移動了畫布
因而在畫圖時是以新原點來產生視圖的,然後合成到屏幕上,超出部分不顯示,最後就是我們看到結果了。
下面來清點一下重要的API,繪制顏色就不贅述了
drawRoundRecf畫圓角矩形
` // 第一種
RectF rectF = new RectF(100,100,400,400);
canvas.drawRoundRect(rectF,30,30,paint_red);
// 第二種 需要api21,一般常用第一種
// canvas.drawRoundRect(100,100,800,400,30,30,paint_red);`
這裡是采用第一種方法畫出來的,參數30(rx),30(ry)是橢圓的兩個半徑,用來確定圓角的弧度。
drawOval畫橢圓
` // 第一種
RectF rectF = new RectF(100,100,500,400);
canvas.drawOval(rectF,paint_red);
// 第二種
canvas.drawOval(100,100,800,400,paint_red);`
通常也是使用第一種,畫橢圓只需要一個矩形即可,橢圓是改矩形的內切
drawArc畫圓弧
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCTxwPi8vILXa0rvW1jxiciAvPg0KCXB1YmxpYyB2b2lkIGRyYXdBcmMoQE5vbk51bGwgUmVjdEYgb3ZhbCwgZmxvYXQgc3RhcnRBbmdsZSwgZmxvYXQgc3dlZXBBbmdsZSwgYm9vbGVhbiB1c2VDZW50ZXIsIEBOb25OdWxsIFBhaW50IHBhaW50KXt9PC9wPg0KCTxwPi8vILXatv7W1jxiciAvPg0KCXB1YmxpYyB2b2lkIGRyYXdBcmMoZmxvYXQgbGVmdCwgZmxvYXQgdG9wLCBmbG9hdCByaWdodCwgZmxvYXQgYm90dG9tLCBmbG9hdCBzdGFydEFuZ2xlLGZsb2F0IHN3ZWVwQW5nbGUsIGJvb2xlYW4gdXNlQ2VudGVyLCBATm9uTnVsbCBQYWludCBwYWludCkge308L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD6/ydLUv7Sz9tXiwO/KudPDwcvN1tSytcTQzte0o6yz/bTL1q7N4rzTyc/By8j9uPayzsr9PC9wPg0KPGJsb2NrcXVvdGU+DQoJPHA+c3RhcnRBbmdsZSAvLyC/qsq8vce2yDwvcD4NCgk8cD5zd2VlcEFuZ2xlIC8vIMmouf29x7bIPC9wPg0KCTxwPnVzZUNlbnRlciAvLyDKx7fxus3W0NDEtePBrLPJ0ru49rfisdW1xM280M48L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cHJlIGNsYXNzPQ=="brush:java;">
` RectF rectF = new RectF(100, 100, 400, 400);
RectF rectF1 = new RectF(200, 200, 500, 500);
canvas.drawArc(rectF, 0, 40, true, paint_green);
canvas.drawArc(rectF1, 0, 40, false, paint_green);`
畫圓弧要清楚,0-40畫弧,首先水平那根線是起點,按順時針40度停止。
這個結合path一起使用會非常強大!(path用法也是內涵滿滿,這裡就不展開敘述了)
這裡看下canvas中的用法
public void drawPath(@NonNull Path path, @NonNull Paint paint){}
傳入路徑,和對應的畫筆即可
` Path path = new Path();
path.moveTo(50,50);
path.quadTo(30,220,320,450);
canvas.drawPath(path,paint_green);`
這裡使用path畫了一條貝塞爾曲線
裁剪涉及到一個Region.Op區域組合的問題
` 假設用region A 去組合region B
public enum Op {
DIFFERENCE(0), //A和B的差集范圍,即A - B,只有在此范圍內的繪制內容才會被顯示;
INTERSECT(1), // 即A和B的交集范圍,只有在此范圍內的繪制內容才會被顯示
UNION(2), //即A和B的並集范圍,即兩者所包括的范圍的繪制內容都會被顯示;
XOR(3), //A和B的補集范圍,此例中即A除去B以外的范圍,只有在此范圍內的繪制內容才會被顯示;
REVERSE_DIFFERENCE(4), //B和A的差集范圍,即B - A,只有在此范圍內的繪制內容才會被顯示;
REPLACE(5); //不論A和B的集合狀況,B的范圍將全部進行顯示,如果和A有交集,則將覆蓋A的交集范圍;
} `
clipPath( ),clipRect( ),clipRegion( );通過Path,Rect,Region的不同組合,幾乎可以支持任意形狀的裁剪區域!
這裡演示一個Region.Op.DIFFERENCE,將畫筆改為FILL,然後
` canvas.clipRect(10, 10, 110, 110); //第一個
canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二個
canvas.drawRect(0, 0, 200, 200, paint_green);`
save():把當前狀態的狀態進行保存,然後放入棧中
restore():把棧頂畫布狀態取出
畫布變換主要包括translate(位移)、scale(縮放)、rotate(旋轉)、skew(傾斜),畫布操作可以幫助我們更加容易的方式制作圖形。
【位移translate】
public void translate(float dx, float dy)
基於當前坐標系的移動,並不是屏幕左上角的原點位置
` //構造一個矩形
Rect rect1 = new Rect(0, 0, 200, 100);
canvas.translate(50, 50);
//在平移畫布前用綠色畫下邊框
canvas.drawRect(rect1, paint_green);
//平移畫布後,再用紅色邊框重新畫下這個矩形
canvas.translate(50, 50);
canvas.drawRect(rect1, paint_red);`
【縮放scale】
public void scale (float sx, float sy),分別是x,y軸的縮放比例
public final void scale (float sx, float sy, float px, float py),x.y軸的縮放比例,px,py表示縮放中心位置
其中當縮放比例為負數時候會根據縮放中心軸進行翻轉
套用網上一個經典的例子(畫筆要設置粗一點,不然會有部分顯示不全)
` canvas.translate(mWidth/2,mHeight/2);
RectF rectf = new RectF(-300,-300,300,300);
for (int i=0;i<15;i++){
canvas.scale(0.8f,0.8f);
canvas.drawRect(rectf,paint_red);
}`
【旋轉 rotate】
public void rotate (float degrees),旋轉角度(順時針)
public final void rotate (float degrees, float px, float py),旋轉角度和控制點
這個在畫表盤啥的很常用。同樣跟位移一樣,旋轉度數也是可以疊加的。
【錯切 skew】
public void skew (float sx, float sy)
float sx:將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值,
float sy:將畫布在y軸方向上傾斜相應的角度,sy為傾斜角度的tan值.
`Rect rect1 = new Rect(10,10,200,100);
canvas.drawRect(rect1, paint_green);
canvas.skew(1,0);//X軸傾斜45度,Y軸不變
canvas.drawRect(rect1, paint_red);`
普通水平繪制
drawText
這個比較簡單,但是需要注意繪制text繪制精確位置使用FontMetrics,主要包含四個參數
ascent = ascent線的y坐標 - baseline線的y坐標;
descent = descent線的y坐標 - baseline線的y坐標;
top = top線的y坐標 - baseline線的y坐標;
bottom = bottom線的y坐標 - baseline線的y坐標;
指定每個文字位置
void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)
void drawPosText (String text, float[] pos, Paint paint)
參數說明
char[] text:要繪制的文字數組
int index::第一個要繪制的文字的索引
int count:要繪制的文字的個數,用來算最後一個文字的位置,從第一個繪制的文字開始算起
float[] pos:每個字體的位置,同樣兩兩一組,如{x1,y1,x2,y2,x3,y3……}
`float []pos=new float[]{80,100,
100,200,
120,300,
140,400};
canvas.drawPosText("1234", pos, paint);`
··
沿路徑繪制
void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
參數說明:
float hOffset : 與路徑起始點的水平偏移距離
float vOffset : 與路徑中心的垂直偏移量
` String string = "測試文字偏移的參數";
Path circlePath = new Path();
circlePath.addCircle(220, 200, 100, Path.Direction.CCW);
canvas.drawPath(circlePath, paint_red);//繪制出路徑原形
Path circlePath2 = new Path();
circlePath2.addCircle(550, 200, 100, Path.Direction.CCW);
canvas.drawPath(circlePath2, paint_red);//繪制出路徑原形
paint_green.setTextSize(30);
//hoffset、voffset參數值全部設為0,看原始狀態是怎樣的
canvas.drawTextOnPath(string, circlePath, 0, 0, paint_green);
//第二個路徑,改變hoffset、voffset參數值
canvas.drawTextOnPath(string, circlePath2, 80, 30, paint_green);`
常用的基本介紹差不多了還有諸如
drawBitmapMesh:只對繪制的Bitmap作用,使其變形drawVertices:使得畫布變形
等等實在撸不動了。
Handler的作用一般是子線程向主線程中傳遞消息,用來主線程處理和UI相關的東西。為什麼要在子線程中用呢,因為如果主線程處理了過多耗時的東西,可能會導致假死,所以一般都
文件下載在App應用中也用到很多,一般版本更新時多要用的文件下載來進行處理,以前也有看過很多大神有過該方面的博客,今天我也自己來實踐一下,寫的一般,還請大家多提意見,共同
Activity是Android四大組件中最基礎也是最常用的組件之一。Activity作為一個應用程序組件,提供了一個與用戶交互的界面。可以這麼說Activity是和用戶
本文介紹了一個使用Handler的Android應用程序,通過該程序,我們可以了解Handler的基本用法。該程序運行效果如下: 點擊But