1. 程式人生 > >自定義View學習筆記 From GcsSloop

自定義View學習筆記 From GcsSloop

一:基礎部分

1.座標系

三個系列方法:
    getLeft():距離父容器左
    getX():距離自身x軸
    getRawX():距離螢幕x軸

2.角度與弧度

180(角度)/deg = π(弧度)/rad

3.顏色

**顏色定義**
ARGB8888    四通道高精度32位   #FFFFFFFF
ARGB4444    四通道低精度16位   #FFFF
RGB565      螢幕預設16位
Alpha8          僅有透明通道8位
**混合模式**
RGB最終顏色=繪製的顏色+(1-繪製顏色的透明度)*Canvas的原色
*繪製顏色/原色=RGB*A(浮點 0~255--0.0f~1.0f)
*demo:0x88ffffff(色) = 0xffffff * (0x88/0xff)
核心程式碼 Paint.setfermode(Porter.MODE)

混合模式

二:進階

1.流程

(1):構造器:佈局檔案引用一般呼叫雙引數的方法
(2):onMeasure()
確定大小,如果對View的寬高進行修改了,不要呼叫 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要呼叫 setMeasuredDimension( widthsize, heightsize); 這個函式。
(3):onSizeChanged():這裡的w,h就是最終的大小
(4):onLayout():child.layout(l,t,r,b)
(5):onDraw()
(6):公共方法與回撥介面

2.Canvas

> 1.速查表
(1)繪製顏色 drawColor, drawRGB, drawARGB 使用單一顏色填充整個畫布
(2)繪製基本形狀 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次為 點、線、矩形、圓角矩形、橢圓、圓、圓弧
(3)繪製圖片 drawBitmap, drawPicture 繪製點陣圖和圖片
(4)繪製文字 drawText, drawPosText, drawTextOnPath 依次為 繪製文字、繪製文字時指定每個文字位置、根據路徑繪製文字
(5)繪製路徑 drawPath 繪製路徑,繪製貝塞爾曲線時也需要用到該函式
(6)頂點操作 drawVertices, drawBitmapMesh 通過對頂點操作可以使影象形變,drawVertices直接對畫布作用、 drawBitmapMesh只對繪製的Bitmap作用
(7)畫布剪裁 clipPath, clipRect 設定畫布的顯示區域
(8)畫布快照 save, restore, saveLayerXxx, restoreToCount, getSaveCount 依次為 儲存當前狀態、 回滾到上一次儲存的狀態、 儲存圖層狀態、 回滾到指定狀態、 獲取儲存次數
(9)畫布變換 translate, scale, rotate, skew 依次為 位移、縮放、 旋轉、錯切
(10)Matrix(矩陣) getMatrix, setMatrix, concat 實際上畫布的位移,縮放等操作的都是影象矩陣Matrix, 只不過Matrix比較難以理解和使用,故封裝了一些常用的方法。
2.畫布操作


(1)位移(translate):移動的是座標系
(2)縮放(scale):
[-∞, -1)===先根據縮放中心放大n倍,再根據中心軸進行翻轉
-1 ===根據縮放中心軸進行翻轉
(-1, 0)===先根據縮放中心縮小到n,再根據中心軸進行翻轉
0===不會顯示,若sx為0,則寬度為0,不會顯示,sy同理
(0, 1)===根據縮放中心縮小到n
1===沒有變化
(1, +∞)===根據縮放中心放大n倍
(3)旋轉(rotate):可疊加
(4)錯切(skew)
引數含義:
float sx:將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值,
float sy:將畫布在y軸方向上傾斜相應的角度,sy為傾斜角度的tan值.
變換後:
X = x + sx * y
Y = sy * x + y
(5)快照(save)和回滾(restore)
save 把當前的畫布的狀態進行儲存,然後放入特定的棧中
saveLayerXxx 新建一個圖層,並放入特定的棧中
restore 把棧中最頂層的畫布狀態取出來,並按照這個狀態恢復當前的畫布
restoreToCount 彈出指定位置及其以上所有的狀態,並按照指定位置的狀態進行恢復
getSaveCount 獲取棧中內容的數量(即儲存次數)
3.圖片文字
(1)drawPicture:
:在AndroidMenifest檔案中application節點下添上 android:hardwareAccelerated=”false”以關閉整個應用的硬體加速。
:Picture錄的是Canvas中繪製的內容。
方法:
public int getWidth () 獲取寬度
public int getHeight () 獲取高度
public Canvas beginRecording (int width, int height) 開始錄製 (返回一個Canvas,在Canvas中所有的繪製都會儲存在Picture中)
public void endRecording () 結束錄製
public void draw (Canvas canvas) 將Picture中內容繪製到Canvas中

// 1.建立Picture
private Picture mPicture = new Picture();

---------------------------------------------------------------

// 2.錄製內容方法
private void recording() {
    // 開始錄製 (接收返回值Canvas)
    Canvas canvas = mPicture.beginRecording(500, 500);
    // 建立一個畫筆
    Paint paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setStyle(Paint.Style.FILL);

    // 在Canvas中具體操作
    // 位移
    canvas.translate(250,250);
    // 繪製一個圓
    canvas.drawCircle(0,0,100,paint);

    mPicture.endRecording();
}

---------------------------------------------------------------

// 3.在使用前呼叫(我在建構函式中呼叫了)
  public Canvas3(Context context, AttributeSet attrs) {
    super(context, attrs);

    recording();    // 呼叫錄製
}

(2)drawBitmap
通過BitmapFactory獲取
// 第一種
public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
// 第二種
public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
// 第三種
public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

3.Path

1.直線方法
(1)moveTo、 setLastPoint、 lineTo 和 close
lineTo (float x, float y):從某個點到引數座標點之間連一條線
moveTo (float x, float y):只改變下次操作的起點,不影響之前,隻影響之後
setLastPoint (float dx, float dy):是重置上一次操作的最後一個點,影響之前的操作也影響之後
close ():close的作用是封閉路徑,與連線當前最後一個點和第一個點並不等價。如果連線了最後一個點和第一個點仍然無法形成封閉圖形,則close什麼 也不做。
(2)addXxx與arcTo
addXXX (…, Path.Direction dir):Direction:CW(順時針)CCW(逆時針)。指的是path轉成點的順序(ABCD ADCB)
arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)引數說明:
oval 圓弧的外切矩形。
startAngle 開始角度
sweepAngle 掃過角度(-360 <= sweepAngle <360)
forceMoveTo 是否強制使用MoveTo
(3)isEmpty、 isRect、isConvex、 set 和 offset
isEmpty:判斷path中是否包含內容。
isRect:判斷path是否是一個矩形,如果是一個矩形的話,會將矩形的資訊存放進引數rect中。
set:將新的path賦值到現有path。
offset:對path進行一段平移,最後的引數das是儲存平移後的path的。
2.貝塞爾曲線
一階曲線:lineTo(),
二階曲線:quadTo(),二階曲線由兩個資料點(A 和 C),一個控制點(B)來描述曲線狀態
三階曲線:cubicTo(),三階曲線由兩個資料點(A 和 D),兩個控制點(B 和 C)來描述曲線狀態
3.其它
(1)rMoveTo, rLineTo, rQuadTo, rCubicTo:rXxx方法的座標使用的是相對位置(基於當前點的位移),而之前方法的座標是絕對位置(基於當前座標系的座標)。
(2)填充模式:
EVEN_ODD 奇偶規則
INVERSE_EVEN_ODD 反奇偶規則
WINDING 非零環繞數規則
INVERSE_WINDING 反非零環繞數規則
setFillType 設定填充規則
getFillType 獲取當前填充規則
isInverseFillType 判斷是否是反向(INVERSE)規則
toggleInverseFillType 切換填充規則(即原有規則與反向規則之間相互切換)
(3)布林操作
boolean op (Path path, Path.Op op)
boolean op (Path path1, Path path2, Path.Op op)
Path.Op. :
DIFFERENCE 差集 Path1中減去Path2後剩下的部分
REVERSE_DIFFERENCE 差集 Path2中減去Path1後剩下的部分
INTERSECT 交集 Path1與Path2相交的部分
UNION 並集 包含全部Path1和Path2
XOR 異或 包含Path1與Path2但不包括兩者相交的部分
(4)邊界
void computeBounds (RectF bounds, boolean exact)
bounds 測量結果會放入這個矩形
exact 是否精確測量,目前這一個引數作用已經廢棄,一般寫true即可。
(5)重置路徑
重置Path有兩個方法,分別是reset和rewind,兩者區別主要有一下兩點:
方法 是否 是否
reset 保留FillType設定 不保留原有資料結構
rewind 不保留FillType設定 保留原有資料結構
選擇權重: FillType > 資料結構
因為“FillType”影響的是顯示效果,而“資料結構”影響的是重建速度。
4.PathMeasure
(1):
PathMeasure(): 建立一個空的PathMeasure
PathMeasure(Path path, boolean forceClosed): 建立 PathMeasure 並關聯一個指定的Path(Path需要已經建立完成)。
*a:不論 forceClosed 設定為何種狀態(true 或者 false), 都不會影響原有Path的狀態,即 Path 與 PathMeasure 關聯之後,之前的的 Path 不會有任何改變。
*b:forceClosed 的設定狀態可能會影響測量結果,如果 Path 未閉合但在與 PathMeasure 關聯的時候設定 forceClosed 為 true 時,測量結果可能會比 Path 實際長度稍長一點,獲取到到是該 Path 閉合時的狀態。
(2):setPath、 isClosed 和 getLength
setPath 是 PathMeasure 與 Path 關聯的重要方法,效果和 建構函式 中兩個引數的作用是一樣的。
isClosed 用於判斷 Path 是否閉合,但是如果你在關聯 Path 的時候設定 forceClosed 為 true 的話,這個方法的返回值則一定為true。
getLength 用於獲取 Path 第一條路徑的總長度,在之前的測試中已經用過了。
(3):boolean getSegment (float startD, float stopD, Path dst, boolean startWithMoveTo)
返回值(boolean)- 判斷擷取是否成功 true 表示擷取成功,結果存入dst中,false 擷取失敗,不會改變dst中內容
startD -開始擷取位置距離 Path 起點的長度 取值範圍: 0 <= startD < stopD <= Path總長度
stopD -結束擷取位置距離 Path 起點的長度 取值範圍: 0 <= startD < stopD <= Path總長度
dst -擷取的 Path 將會新增到 dst 中 注意: 是新增,而不是替換
startWithMoveTo 起始點是否使用 moveTo 用於保證擷取的 Path 第一個點位置不變
(4):nextContour
我們知道 Path 可以由多條曲線構成,但不論是 getLength , getgetSegment 或者是其它方法,都只會在其中第一條線段上執行,而這個 nextContour 就是用於跳轉到下一條曲線到方法,如果跳轉成功,則返回 true, 如果跳轉失敗,則返回 false。
(5):getPosTan
boolean getPosTan (float distance, float[] pos, float[] tan)
返回值(boolean) -判斷獲取是否成功 true表示成功,資料會存入 pos 和 tan 中,
false 表示失敗,pos 和 tan 不會改變
distance -距離 Path 起點的長度 取值範圍: 0 <= distance <= getLength
pos -該點的座標值 當前點在畫布上的位置,有兩個數值,分別為x,y座標。
tan -該點的正切值 當前點在曲線上的方向,使用 Math.atan2(tan[1], tan[0]) 獲取到正切角的弧度值。
(6):getMatrix
boolean getMatrix (float distance, Matrix matrix, int flags)
返回值(boolean) -判斷獲取是否成功 true表示成功,資料會存入matrix中,false 失敗,matrix內容不會改變
distance -距離 Path 起點的長度 取值範圍: 0 <= distance <= getLength
matrix -根據 falgs 封裝好的matrix 會根據 flags 的設定而存入不同的內容
flags -規定哪些內容會存入到matrix中 可選擇
POSITION_MATRIX_FLAG(位置)
ANGENT_MATRIX_FLAG(正切)
(7)Path & SVG
該圖片來自這個開源庫 ->PathView(https://github.com/geftimov/android-pathview)
SVG 轉 Path 的解析可以用這個庫 -> AndroidSVG(https://bigbadaboom.github.io/androidsvg/)