標籤:map 主線程 mes 計算公式 渲染 drawtext 1.3 final view
- 6.1 螢幕的尺寸資訊
- 6.1.1 螢幕參數
- 6.1.2 系統螢幕密度
- 6.1.3 獨立像素密度dp
- 6.1.4 單位轉換
- 6.2 2D繪圖基礎
- 6.3 Android XML繪圖
- 6.3.1 Bitmap
- 6.3.2 Shape
- 6.3.3 Layer
- 6.3.4 Selector
- 6.4 Android繪圖技巧
- 6.4.1 Canvas
- 6.4.2 Layer圖層
- 6.5 Android影像處理之色彩特效處理
- 6.5.1 色彩矩陣分析
- 6.5.2 Android顏色矩陣——ColorMatrix
- 6.5.3 常用映像顏色矩陣處理效果
- 6.5.4 像素點分析
- 6.5.5 常用映像像素點處理效果
- 6.6 Android影像處理之圖形特效處理
- 6.6.1 Android變形矩陣——Matrix
- 6.6.2 像素塊分析
- 6.7 Android影像處理之畫筆特效處理
- 6.7.1 PorterDuffXfermode
- 6.7.2 Shader
- 6.7.3 PathEffect
- 6.8 View之孿生兄弟——SurfaceView
- 6.8.1 SurfaceView與View的區別
- 6.8.2 SurfaceView的使用
- 6.8.3 SurfaceView執行個體
由於這一章比較難理解,所以大部分知識點都是摘抄原文的,如果是沒學習過線性代數的同學,那就難上加難了,不過克服它,是你進階進階工程師的必經之路,文章比較長,請耐心觀看
無知識點
- 螢幕大小:螢幕對角線的長度,通常用寸來度量
- 解析度:手機螢幕的像素點個數
- PPI:每英吋像素,又稱DPI,由對角線像素點除以螢幕大小獲得
Android系統使用mdpi即密度值為160的螢幕作為標準,在這個螢幕上1px=1dp
ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12
這裡加0.5f的巧用目的是:四捨五入
dp==dip
系統提供了TypedValue類協助我們轉換
Paint作為一個重要的元素有以下方法:
- setAntiAlias():設定畫筆的鋸齒效果
- setColor():設定畫筆的顏色
- setARGB():設定畫筆的A、R、G、B值
- setAlpha():設定畫筆的Alpha值
- setTextSize():設定字型的尺寸
- setStyle():設定畫筆的風格(空心或實心)
- setStrokeWidth():設定空心邊框的寬度
設定Paint的Style可以畫出空心或者實心的矩形:
- paint.setStyle(Paint.Style.STROKE):空心效果
- paint.setStyle(Paint.Style.FILL):實心效果
系統通過提供的Canvas對象來提供繪圖方法:
- canvas.drawPoint(x, y, paint):繪製點
- canvas.drawLine(startX, startY ,endX, endY, paint):繪製直線
- canvas.drawLines(new float[]{startX1, startY1, endX1, endY1,……,startXn, startYn, endXn, endYn}, paint):繪製多條直線
- canvas.drawRect(left, top, right, bottom, paint):繪製矩形
- canvas.drawRoundRect(left, top, right, bottom, radiusX, radiusY, paint):繪製圓角矩形
- canvas.drawCircle(circleX, circleY, radius, paint):繪製圓
- canvas.drawOval(left, top, right, bottom, paint):繪製橢圓
- canvas.drawText(text, startX, startY, paint):繪製文本
- canvas.drawPosText(text, new float[]{X1,Y1,X2,Y2,……Xn,Yn}, paint):在指定位置繪製文本
- Path path=new Path();
path.moveTo(50, 50);
path.lineTo(100, 100);
path.lineTo(100, 300);
path.lineTo(300, 50);
canvas.drawPath(path, paint):繪製路徑
- paint.setStyle(Paint.Style.STROKE);
drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint):繪製扇形
- paint.setStyle(Paint.Style.STROKE);
drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint):繪製弧形
- paint.setStyle(Paint.Style.FILL);
drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint):繪製實心扇形
- paint.setStyle(Paint.Style.FILL);
drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint):繪製實心弧形
無知識點
通過這樣在XML中使用Bitmap就可以將圖片直接轉換成了Bitmap在程式中使用
通過Shape可以在XML中繪製各種形狀
下面通過漸層來實現的陰影製作效果
通過Layer會產生圖片依次疊加的效果
Selector的作用在於協助開發人員實現靜態繪圖中的事件反饋,通過給不同的事件設定不同的映像,從而在程式中根據使用者輸入,返回不同的效果
下面這個例子實現了一個具有點擊反饋效果的、圓角舉證Selector
無知識點
Canvas提供了以下幾種非常有用的方法:
- Canvas.save():儲存畫布,將之前所有已繪製映像儲存起來,讓後續的操作就好像在一個新的圖層上操作一樣
- Canvas.restore():在save()之後繪製的所有映像與save()之前的映像進行合并,可以理解為Photoshop中的合并圖層操作
- Canvas.translate():畫布平移
- Canvas.roate():畫布翻轉
通過一個執行個體——儀錶盤,來理解這幾個方法,將儀錶盤分為以下幾個元素:
- 儀錶盤:外面的大圓盤
- 刻度標記:包含四個長的刻度標記和其他短的刻度標記
- 刻度值:包含長刻度標記對應的大的刻度值和其他小的刻度值
- 指標:中間的指標,一粗一細兩根指標
儀錶盤……見經典代碼案例一
一張複雜的畫可以由很多個圖層疊加起來,形成一個複雜的映像,使用saveLayer()方法來建立一個圖層,圖層同樣是基於棧的結構進行管理的
Android通過調用saveLayer()方法,saveLayerAlpha()方法將一個圖層入棧,使用restore()方法、restoreToCount()方法將一個圖層出棧,仿照API Demos裡面的一個執行個體來使用Layer
- 當透明度為127時,即半透明
- 當透明度為255時,即完全不透明
- 當透明度為0時,即完全透明
Bitmap圖片都是由點陣和顏色值組成的,所謂點陣就是一個包含像素的矩陣,每一個元素對應著圖片的一個像素。而顏色值——ARGB,分別對應透明度、紅、綠、藍這四個通道分量,它們共同決定了每個像素點顯示的顏色
在色彩處理中,我們通常用三個角度描述一張圖片:
- 色調:物體傳播的顏色
- 飽和度:顏色的純度,從0(灰)-100%(飽和)來進行描述
- 亮度:顏色的相對明暗程度
而在Android中,系統會使用一個顏色矩陣——ColorMatrix,來處理這些色彩的效果,Android中的顏色矩陣是4X5的數字矩陣,他用來對顏色色彩進行處理,而對於每一個像素點,都有一個顏色分量矩陣來儲存ARGB值
根據前面對矩陣A、C的定義,通過矩陣乘法運演算法則,可以得到:
矩陣運算的乘法計算過程如下:
我們觀察顏色矩陣A
從這個公式可以發現
- 第一行的abcde用來決定新的顏色值R——紅色
- 第二行的fghij用來決定新的顏色值G——綠色
- 第三行的kimno用來決定新的顏色值B——藍色
- 第四行的pqrst用來決定新的顏色值A——透明度
- 矩陣A中的第五列——ejot值分別用來決定每個分量中的offset,即位移量
通過一個小例子來講解:
首先重新看一下矩陣變換計算公式,以R分量為例,計算過程如下:
如果讓a=1,b,c,d,e都等於0,那麼計算的結果為R1=R,因此我們可以構建一個矩陣
如果把這個矩陣公式帶入R1=AC,那麼根據矩陣的乘法運演算法則,可以得到R1=R。因此,這個矩陣通常是用來作為初始的顏色矩陣來使用,他不會對原有顏色進行任何變化
那麼當我們要變換顏色值的時候,通常有兩種方法。一個是直接改變顏色的offset,即位移量的值來修改顏色的分量。另一種方法直接改變對應RGBA值的係數來調整顏色分量的值
從前面的分析中,可以知道要修改R1的值,只要將第五列的值進行修改即可。即改變顏色的位移量,其它值儲存初始矩陣的值,
在上面這個矩陣中,我們修改了R、G所對應的顏色位移量,那麼最後的處理結果就是映像的紅色、綠色分別增加了100。而我們知道,紅色混合綠色會得到黃色,所以最終的顏色處理結果就是讓整個圖片的色調偏黃色
如果修改顏色分量中的某個係數值,而其他只依然儲存初始矩陣的值,
在上面這個矩陣中,改變了G分量所對應的係數g,這樣在矩形運算後G分量會變成以前的兩倍,最終效果就是映像的色調更加偏綠
下面通過執行個體看看如何通過矩陣改變映像的色調、飽和度和亮度:
- 色調:setRotate(int axis, float degree),第一個參數分別使用0、1、2代表Red、Green、Blue三種顏色,第二參數需要處理的值
- 飽和度:setSaturation(float sat),參數代表設定飽和度的值
- 亮度:setScale(float rscale,float gscale,float bscale,float ascale),參數分別是紅、綠、藍、透明度的亮度大小值
除了單獨使用上面三種方式來進行顏色效果處理之外,還提供了postConcat()方法來將矩陣的作用效果混合,從而疊加處理效果
通過SeekBar調節色調、飽和度、亮度……見經典代碼回顧案例二
類比4x5的顏色矩陣……見經典代碼回顧案例三
在Android中,系統系統提供了Bitmap.getPixels()方法來幫我們提取整個Bitmap中的像素點,並儲存在一個數組中:
這幾個參數的具體含義如下:
- pixels:接收位元影像顏色值的數組
- offset:寫入到pixels[]中的第一個像素索引值
- stride:pixels[]中的行間距
- x:從位元影像中讀取的第一個像素的x座標值
- y:從位元影像中讀取的第一個像素的y座標值
- width:從每一行中讀取的像素寬度
- height:讀取的行數
通常使用如下代碼:
接下來擷取每個像素具體的ARGB值:
接下來就是修改像素值,產生新的像素值
最後使用我們的新像素值
底片效果、老照片效果、浮雕效果……見經典代碼回顧案例四
無知識點
對於圖形變換,系統提供了3x3的舉證來處理:
與顏色矩陣一樣,計算方法通過矩陣乘法:
與顏色矩陣一樣,也有一個初始矩陣:
映像的變形處理包含以下四類基本變換:
- Translate:平移變換
- Rotate:旋轉變換
- Scale:縮放變換
- Skew:錯切變換
平移變換:即對每個像素點都進行平移變換,通過計算可以發現如下平移公式:
旋轉變換:通過以下三步驟完成以任意點為旋轉中心的旋轉變換
- 將座標原點平移到O點
- 使用前面講的以座標原點為中心的旋轉方法進行旋轉變換
- 將座標原點還原
縮放變換:縮放變換的效果計算公式如下
錯切變換:錯切變換的效果計算公式如下
瞭解四種圖形變換矩陣,可以通過setValues()方法將一個一維數群組轉換為圖形變換矩陣:
Android中Matrix類也幫我們封裝好了幾個操作方法:
- matrix.setRotate():旋轉變換
- matrix.setTranslate():平移變換
- matrix.setScale():縮放變換
- matrix.setSkew():錯切變換
- pre()和post():提供矩陣的前乘和後乘運算
舉個例子說明前乘和後乘的不同運算方式:
- 先平移到(300, 100)
- 再旋轉45度
- 最後平移到(200, 200)
如果使用後乘運算,代碼如下:
如果使用前乘運算,代碼如下:
drawBitmapMesh()與操縱像素點來改變色彩的原理類似,只不過是把映像分成了一個個的小塊,然後通過改變每一個映像塊來修改整個映像:
參數分析:
- bitmap:將要扭曲的映像
- meshWidth:需要的橫向網格數目
- meshHeight:需要的縱向網格數目
- verts:網格交叉點的座標數組
- vertOffset:verts數組中開始跳過的(X,Y)座標組的數目
飄動的旗子……見經典代碼回顧案例五
之前繪圖的時候也提到過畫筆的一些方法,這裡就不再介紹
PorterDuffXfermod設定的是兩個圖層交集地區的顯示方式,dst是先畫的圖形,而src是後畫的圖形
以一個圓角圖片為例子:
,由於圖片過大,只能看出一邊角
刮刮卡效果……見經典代碼回顧案例六
Shader又被稱為著色器。渲染器,它可以實現渲染,漸層等效果,Android中的Shader包括以下幾種:
- BitmapShader:位元影像Shader
- LinearGradient:線性Shader
- RadialGradient:光束Shader
- SweepGradient:梯形Shader
- ComposeShader:混合Shader
其中BitmapShader有三種模式可以選擇:
- CLAMP展開:展開的是圖片最後的那一個像素,不斷重複
- REPEAT重複:橫向,縱向不斷重複
- MIRROR鏡像:橫向不斷翻轉重複,縱向不斷翻轉重複
下面看下例子說明,圓形圖片:
下面把TileMode改為REPEAT:
使用LinearGradient:
結合前面的PorterDuffXfermode和剛學的LinearGradient,製作出倒影的片
倒影圖片效果……見經典代碼回顧案例七
先上一張直觀的圖:
Android提供的幾種繪製PathEffect方式:
- 沒效果
- CornerPathEffect:拐彎角變得圓滑
- DiscretePathEffect:線段上會產生許多雜點
- DashPathEffect:繪製虛線,用一個資料來設定各個點之間的間隔
- PathDashPathEffect:繪製虛線,可以使用方形點虛線和圓形點虛線
- ComposePathEffect:可任意組合兩種路徑(PathEffect)的特性
我們通過一個執行個體來認識這些效果:
每繪製一個Path,就將畫布平移,從而讓各種PathEffect依次繪製出來
無知識點
View的繪製重新整理間隔時間為16ms,如果在16ms內完成你所需要執行的所有操作,那麼在使用者視覺上,就不會產生卡頓的感覺,否則,就會出現卡頓,所以可以考慮使用SurfaceView來替代View的繪製
通常在Log會看到這樣的提示:
SurfaceView與View的主要區別:
- View主要適用於主動更新的情況下,而surfaceVicw主要適用於被動更新,例如頻繁重新整理
- View在主線程中對畫面進行重新整理,而surfaceView通常會通過一 個子線程來進行頁面的重新整理
- View在繪製時沒有使用雙緩衝機制,而surfaceVicw在底層實現機制中就已經實現了雙緩衝機制
總結一句話就是,如果你的自訂View需要頻繁重新整理,或者重新整理資料處理量比較大,托福機經就可以考慮使用SurfaceView替代View
SurfaceView使用步驟:
- 建立SurfaceView繼承自SurfaceView,並實現兩個介面——SurfaceHolder.Callback和Runnable
- 初始化SurfacHolder對象,並註冊SurfaceHolder的回調方法
- 通過SurfacHolder對象lockCanvas()方法獲得Canvas對象進行繪製,並通過unlockCanvasAndPost(mCanvas)方法對畫布內容進行提交
整個使用SurfaceView的模板代碼:
唯一注意的是,在繪製中將mHolder.unlockCanvasAndPost(mCanvas)方法放到finally代碼塊中,保證每次都能將內容提交
正弦曲線……見經典代碼回顧案例八
繪圖板……見經典代碼回顧案例九
布局檔案
Activity檔案
布局檔案
Activity檔案
關鍵點:將一個顏色矩陣傳入畫筆,然後畫出原始的圖在建立的圖上面
布局檔案
Activity檔案
工具類
本人也是懵逼,沒有搞懂這個例子
經典回顧源碼下載
github:https://github.com/CSDNHensen/QunYingZhuang
Android群英傳知識點回顧——第六章:Android繪圖機制與處理技巧