安卓自定義View進階: 圖片文字
在上一篇文章Canvas之畫布操作中我們瞭解了畫布的一些基本操作方法,本次瞭解一些繪製圖片文字相關的內容。如果你對前幾篇文章講述的內容熟練掌握的話,那麼恭喜你,本篇結束之後,大部分的自定義View已經難不倒你了,當然了,這並不是終點,接下來還會有更加炫酷的技能。
一.Canvas的常用操作速查表
操作型別 | 相關API | 備註 |
---|---|---|
繪製顏色 | drawColor, drawRGB, drawARGB | 使用單一顏色填充整個畫布 |
繪製基本形狀 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次為 點、線、矩形、圓角矩形、橢圓、圓、圓弧 |
繪製圖片 | drawBitmap, drawPicture | 繪製點陣圖和圖片 |
繪製文字 | drawText, drawPosText, drawTextOnPath | 依次為 繪製文字、繪製文字時指定每個文字位置、根據路徑繪製文字 |
繪製路徑 | drawPath | 繪製路徑,繪製貝塞爾曲線時也需要用到該函式 |
頂點操作 | drawVertices, drawBitmapMesh | 通過對頂點操作可以使影象形變,drawVertices直接對畫布作用、 drawBitmapMesh只對繪製的Bitmap作用 |
畫布剪裁 | clipPath, clipRect | 設定畫布的顯示區域 |
畫布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次為 儲存當前狀態、 回滾到上一次儲存的狀態、 儲存圖層狀態、 回滾到指定狀態、 獲取儲存次數 |
畫布變換 | translate, scale, rotate, skew | 依次為 位移、縮放、 旋轉、傾斜 |
Matrix(矩陣) | getMatrix, setMatrix, concat | 實際上畫布的位移,縮放等操作的都是影象矩陣Matrix, 只不過Matrix比較難以理解和使用,故封裝了一些常用的方法。 |
二.Canvas基本操作詳解
1.繪製圖片
繪製有兩種方法,drawPicture(向量圖) 和 drawBitmap(點陣圖),接下來我們一一瞭解。
(1)drawPicture
使用Picture前請關閉硬體加速,以免引起不必要的問題!
使用Picture前請關閉硬體加速,以免引起不必要的問題!
使用Picture前請關閉硬體加速,以免引起不必要的問題!
在AndroidMenifest檔案中application節點下添上 android:hardwareAccelerated=”false”以關閉整個應用的硬體加速。
更多請參考這裡:Android的硬體加速及可能導致的問題
關於drawPicture一開始還是挺讓人費解的,不過嘛,我們接下來慢慢研究一下它的用途。
既然是drawPicture就要了解一下什麼是Picture。 顧名思義,Picture的意思是圖片。
不過嘛,我覺得這麼用圖片這個名詞解釋Picture是不合適的,為何這麼說?請看其官方文件對Picture的解釋:
A Picture records drawing calls (via the canvas returned by beginRecording) and can then play them back into Canvas (via draw(Canvas) or drawPicture(Picture)).For most content (e.g. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any method-call overhead.
好吧,我知道很多人對這段鳥語是看不懂的,至於為什麼要放在這裡,僅僅是為了顯得更加專業(偷笑)。
下面我就對這段不明覺厲的鳥語用通俗的話翻譯一下:
某一天小萌想在朋友面前顯擺一下,於是在單槓上來了一個後空翻,動作姿勢請參照下圖:
朋友都說 恩,很不錯。 想再看一遍 (〃ω〃)。ヽ(〃∀〃)ノ。⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
於是小萌又來了一遍,如是幾次之後,小萌累的吐血三升。
於是小萌機智的想,我何不能用手機將我是颯爽英姿錄下來呢,直接儲存成為後空翻.avi 下次想顯擺的時候直接拿出手機,點一下播放就行了,省時省力。
小萌被自己的機智深深的折服了,然後Picture就誕生啦。(╯‵□′)╯︵┻━┻掀桌,坑爹呢,這劇情跳躍也忒大了吧。
好吧,言歸正傳,這次我們瞭解的Picture和上文中的錄影功能是類似的,只不過我們Picture錄的是Canvas中繪製的內容。
我們把Canvas繪製點,線,矩形等諸多操作用Picture錄製下來,下次需要的時候拿來就能用,使用Picture相比於再次呼叫繪圖API,開銷是比較小的,也就是說對於重複的操作可以更加省時省力。
PS:你可以把Picture看作是一個錄製Canvas操作的錄影機。
瞭解了Picture的概念之後,我們再瞭解一下Picture的相關方法。
相關方法 | 簡介 |
---|---|
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中 |
public static Picture createFromStream (InputStream stream) | (已廢棄)通過輸入流建立一個Picture |
public void writeToStream (OutputStream stream) | (已廢棄)將Picture中內容寫出到輸出流中 |
上面表格中基本上已經列出了Picture的所有方法,其中getWidth和getHeight沒什麼好說的,最後兩個已經廢棄也自然就不用關注了,排除了這些方法之後,只剩三個方法了,接下來我們就比較詳細的瞭解一下:
很明顯,beginRecording 和 endRecording 是成對使用的,一個開始錄製,一個是結束錄製,兩者之間的操作將會儲存在Picture中。
使用示例:
準備工作:
錄製內容,即將一些Canvas操作用Picture儲存起來,錄製的內容是不會直接顯示在螢幕上的,只是儲存起來了而已。
12345678910111213141516171819202122232425262728293031 | // 1.建立PictureprivatePicture mPicture=newPicture();---------------------------------------------------------------// 2.錄製內容方法privatevoidrecording(){// 開始錄製 (接收返回值Canvas)Canvas canvas=mPicture.beginRecording(500,500);// 建立一個畫筆Paint paint=newPaint();paint.setColor(Color.BLUE);paint.setStyle(Paint.Style.FILL);// 在Canvas中具體操作// 位移canvas.translate(250,250);// 繪製一個圓canvas.drawCircle(0,0,100,paint);mPicture.endRecording();}---------------------------------------------------------------// 3.在使用前呼叫(我在建構函式中呼叫了)publicCanvas3(Context context,AttributeSet attrs){super(context,attrs);recording();// 呼叫錄製} |
具體使用:
Picture雖然方法就那麼幾個,但是具體使用起來還是分很多情況的,由於錄製的內容不會直接顯示,就像儲存的視訊不點選播放不會自動播放一樣,同樣,想要將Picture中的內容顯示出來就需要手動呼叫播放(繪製),將Picture中的內容繪製出來可以有以下幾種方法:
序號 | 簡介 |
---|---|
1 | 使用Picture提供的draw方法繪製。 |
2 | 使用Canvas提供的drawPicture方法繪製。 |
3 | 將Picture包裝成為PictureDrawable,使用PictureDrawable的draw方法繪製。 |
以上幾種方法主要區別:
主要區別 | 分類 | 簡介 |
---|---|---|
是否對Canvas有影響 | 1有影響 2,3不影響 |
此處指繪製完成後是否會影響Canvas的狀態(Matrix clip等) |
可操作性強弱 | 1可操作性較弱 2,3可操作性較強 |
此處的可操作性可以簡單理解為對繪製結果可控程度。 |
幾種方法簡介和主要區別基本就這麼多了,接下來對於各種使用方法一一詳細介紹:
1.使用Picture提供的draw方法繪製:
12 | // 將Picture中的內容繪製在Canvas上mPicture.draw(canvas); |
PS:這種方法在比較低版本的系統上繪製後可能會影響Canvas狀態,所以這種方法一般不會使用。
2.使用Canvas提供的drawPicture方法繪製
drawPicture有三種方法:
12345 | publicvoiddrawPicture(Picture picture)publicvoiddrawPicture(Picture picture,Rect dst)publicvoiddrawPicture(Picture picture,RectF dst) |
和使用Picture的draw方法不同,Canvas的drawPicture不會影響Canvas狀態。
簡單示例:
1 | canvas.drawPicture(mPicture,newRectF(0,0,mPicture.getWidth(),200)); |
*PS:對照上一張圖片,可以比較明顯的看出,繪製的內容根據選區進行了縮放。 *
3.將Picture包裝成為PictureDrawable,使用PictureDrawable的draw方法繪製。
123456 | // 包裝成為DrawablePictureDrawable drawable=newPictureDrawable(mPicture);// 設定繪製區域 -- 注意此處所繪製的實際內容不會縮放drawable.setBounds(0,0,250,mPicture.getHeight());// 繪製drawable.draw(canvas); |
PS:此處setBounds是設定在畫布上的繪製區域,並非根據該區域進行縮放,也不是剪裁Picture,每次都從Picture的左上角開始繪製。
注意:在使用Picture之前請關閉硬體加速,以免引起不必要的問題,如何關閉請參考這裡: Android的硬體加速及可能導致的問題
(2)drawBitmap
其實一開始知道要講Bitmap我是拒絕的,為什麼呢?因為Bitmap就是很多問題的根源啊有木有,Bitmap可能導致記憶體不足,記憶體洩露,ListView中的複用混亂等諸多問題。想完美的掌控Bitmap還真不是一件容易的事情。限於篇幅本文對於Bitmap不會過多的展開,只講解一些常用的功能,關於Bitmap詳細內容,以後開專題講解QAQ。
既然要繪製Bitmap,就要先獲取一個Bitmap,那麼如何獲取呢?
獲取Bitmap方式:
序號 | 獲取方式 | 備註 |
---|---|---|
1 | 通過Bitmap建立 | 複製一個已有的Bitmap(新Bitmap狀態和原有的一致) 或者 建立一個空白的Bitmap(內容可改變) |
2 | 通過BitmapDrawable獲取 | 從資原始檔 記憶體卡 網路等地方獲取一張圖片並轉換為內容不可變的Bitmap |
3 | 通過BitmapFactory獲取 | 從資原始檔 記憶體卡 網路等地方獲取一張圖片並轉換為內容不可變的Bitmap |
通常來說,我們繪製Bitmap都是讀取已有的圖片轉換為Bitmap繪製到Canvas上。
很明顯,第1種方式不能滿足我們的要求,暫時排除。
第2種方式雖然也可滿足我們的要求,但是我不推薦使用這種方式,至於為什麼在後續詳細講解Drawable的時候會說明,暫時排除。
第3種方法我們會比較詳細的說明一下如何從各個位置獲取圖片。
通過BitmapFactory從不同位置獲取Bitmap:
資原始檔(drawable/mipmap/raw):
1 | Bitmap bitmap=BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap); |
資原始檔(assets):
12345678 | Bitmap bitmap=null;try{InputStream is=mContext.getAssets().open("bitmap.png");bitmap=BitmapFactory.decodeStream(is);is.close();}catch(IOExceptione){e.printStackTrace();} |
記憶體卡檔案:
1 | Bitmap bitmap=BitmapFactory.decodeFile("/sdcard/bitmap.png"); |
網路檔案:
123 | // 此處省略了獲取網路輸入流的程式碼Bitmap bitmap=BitmapFactory.decodeStream(is);is.close(); |
既然已經獲得到了Bitmap,那麼就開始本文的重點了,將Bitmap繪製到畫布上。
繪製Bitmap:
依照慣例先預覽一下drawBitmap的常用方法:
123456789 | // 第一種publicvoiddrawBitmap(Bitmap bitmap,Matrix matrix,Paint paint)// 第二種publicvoiddrawBitmap(Bitmap bitmap,floatleft,floattop,Paint paint)// 第三種publicvoiddrawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint)publicvoiddrawBitmap(Bitmap bitmap,Rect src,RectF dst,Paint paint) |
第一種方法中後兩個引數(matrix, paint)是在繪製的時候對圖片進行一些改變,如果只是需要將圖片內容繪製出來只需要如下操作就可以了:
PS:圖片左上角位置預設為座標原點。
1 | canvas.drawBitmap(bitmap,newMatrix(),newPaint()); |
關於Matrix和Paint暫時略過吧,一展開又是囉囉嗦嗦一大段,反正挖坑已經是常態了,大家應該也習慣了(PAP).
第二種方法就是在繪製時指定了圖片左上角的座標(距離座標原點的距離):
注意:此處指定的是與座標原點的距離,並非是與螢幕頂部和左側的距離, 雖然預設狀態下兩者是重合的,但是也請注意分別兩者的不同。
1 | canvas.drawBitmap(bitmap,200,500,newPaint()); |
第三種方法比較有意思,上面多了兩個矩形區域(src,dst),這兩個矩形選區是幹什麼用的?
名稱 | 作用 |
---|---|
Rect src | 指定繪製圖片的區域 |
Rect dst 或RectF dst | 指定圖片在螢幕上顯示(繪製)的區域 |
示例:
1234567891011 | // 將畫布座標系移動到畫布中央canvas.translate(mWidth/2,mHeight/2);// 指定圖片繪製區域(左上角的四分之一)Rect src=newRect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);// 指定圖片在螢幕上顯示的區域Rect dst=newRect(0,0,200,400);// 繪製圖片canvas.drawBitmap(bitmap,src,dst,null); |
詳解:
上面是以繪製該圖為例,用src指定了圖片繪製部分的區域,即下圖中紅色方框標註的區域。
在上一篇文章Canvas之畫布操作中我們瞭解了畫布的一些基本操作方法,本次瞭解一些繪製圖片文字相關的內容。如果你對前幾篇文章講述的內容熟練掌握的話,那麼恭喜你,本篇結束之後,大部分的自定義View已經難不倒你了,當然了,這並不是終點,接下來還會有更加炫酷的技能。
一.Canva
在上一篇文章Canvas之畫布操作中我們瞭解了畫布的一些基本操作方法,本次瞭解一些繪製圖片文字相關的內容。如果你對前幾篇文章講述的內容熟練掌握的話,那麼恭喜你,本篇結束之後,大部分的自定義View已經難不倒你了,當然了,這並不是終點,接下來還會有更加炫酷的技能。
一.Canva
Android 手勢檢測,主要是 GestureDetector 相關內容的用法和注意事項,本文依舊屬於事件處理這一體系,部分內容會涉及到之前文章提及過的知識點,如果你沒看過之前的文章,可以到 自定義 View 系列 來檢視這些內容。
在開發 Android 手機應用過程中,可
Android 多點觸控詳解,在前面的幾篇文章中我們大致瞭解了 Android 中的事件處理流程和一些簡單的處理方案,本次帶大家瞭解 Android 多點觸控相關的一些知識。
多點觸控 ( Multitouch,也稱 Multi-touch ),即同時接受螢幕上多個點的人機互動
本文帶大家瞭解 Android 特殊形狀控制元件的事件處理方式,主要是利用了 Region 和 Matrix 的一些方法,超級實用的事件處理方案,相信看完本篇之後,任何奇葩控制元件的事件處理都會變得十分簡單。
不得不說,Android 對事件體系封裝的非常棒,即便對事件體系不太
Android MotionEvent 詳解,之前用了兩篇文章 事件分發機制原理 和 事件分發機制詳解 來講解事件分發,而作為事件分發主角之一的 MotionEvent 並沒有過多的說明,本文就帶大家瞭解 MotionEvent 的相關內容,簡要介紹觸控事件,主要包括 單點觸控、多點
Android 事件分發機制詳解,在上一篇文章 事件分發機制原理 中簡要分析了一下事件分發機制的原理,原理是十分簡單的,一句話就能總結:責任鏈模式,事件層層傳遞,直到被消費。 雖然原理簡單,但是隨著 Android 不斷的發展,實際運用場景也越來越複雜,所以想要徹底玩轉事件分發機制還
本篇依舊屬於Matrix,主要講解Camera,Android下有很多相機應用,其中的美顏相機更是不少,不過今天這個Camera可不是我們平時拍照的那個相機,而是graphic包下的Camera,專業給View拍照的相機,不過既然是相機,作用都是類似的,主要是將3D的內容拍扁變成2D
這應該是目前最詳細的一篇講解Matrix的中文文章了,在上一篇文章Matrix原理中,我們對Matrix做了一個簡單的瞭解,偏向理論,在本文中則會詳細的講解Matrix的具體用法,以及與Matrix相關的一些實用技巧。
⚠️ 警告:測試本文章示例之前請關閉硬體加速。
本文內容偏向理論,和 畫布操作 有重疊的部分,本文會讓你更加深入的瞭解其中的原理。
本篇的主角Matrix,是一個一直在後臺默默工作的勞動模範,雖然我們所有看到View背後都有著Matrix的功勞,但我們卻很少見到它,本篇我們就看看它是何方神聖吧。
由於Goog
可以看到,在經過 Path之基本操作 Path之貝塞爾曲線 和 Path之完結篇 後, Path中各類方法基本上都講完了,表格中還沒有講解到到方法就是矩陣變換了,難道本篇終於要講矩陣了? 非也,矩陣這一部分仍在後面單獨講解,本篇主要講解 PathMeasure 這個類與 Path 的
在上一篇文章Path之基本操作中我們瞭解了Path的基本使用方法,本次瞭解Path中非常非常非常重要的內容-貝塞爾曲線。
一.Path常用方法表
為了相容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上
在上一篇Canvas之圖片文字中我們瞭解瞭如何使用Canvas中繪製圖片文字,結合前幾篇文章,Canvas的基本操作已經差不多完結了,然而Canvas不僅僅具有這些基本的操作,還可以更加炫酷,本次會了解到path(路徑)這個Canvas中的神器,有了這個神器,就能創造出更多炫(zhu
本章節為什麼要叫進階篇?(雖然講的是基礎內容),因為從本篇開始,將會逐漸揭開自定義View的神祕面紗,每一篇都將比上一篇內容更加深入,利用所學的知識能夠製作更加炫酷自定義View,就像在臺階上一樣,每一篇都更上一層,幫助大家一步步走向人生巔峰,出任CEO,迎娶白富美。 誤
經歷過前兩篇 Path之基本操作 和 Path之貝塞爾曲線 的講解,本篇終於進入Path的收尾篇,本篇結束後Path的大部分相關方法都已經講解完了,但Path還有一些更有意思的玩法,應該會在後續的文章中出現。
一.Path常用方法表
為了相容性(偷懶) 本表格中去除
0. 前言
Android 縮放手勢檢測,ScaleGestureDetector 相關內容的用法和注意事項,本文依舊屬於事件處理這一體系,在大多數的情況下,縮放手勢都不是單獨存在的,需要配合其它的手勢來使用,所以推薦配合 手勢檢測(GestureDetector) 一
Canvas之畫布操作
上一篇Canvas之繪製基本形狀中我們瞭解瞭如何使用Canvas繪製基本圖形,本次瞭解一些基本的畫布操作。
本來想把畫布操作放到後面部分的,但是發現很多圖形繪製都離不開畫布操作,於是先講解一下畫布的基本操作方法。
在上一篇文章Path之基本圖形中我們瞭解了Path的基本使用方法,本次瞭解Path中非常非常非常重要的內容-貝塞爾曲線。
一.Path常用方法表
為了相容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上才新增的方法。忍不住吐槽一下,為啥看起來有些順手就能寫的
在上一篇Canvas之圖片文字中我們瞭解瞭如何使用Canvas中繪製圖片文字,結合前幾篇文章,Canvas的基本操作已經差不多完結了,然而Canvas不僅僅具有這些基本的操作,還可以更加炫酷,本次會了解到path(路徑)這個Canvas中的神器,有了這個神器,就能創造出更多炫(
經歷過前兩篇 Path之基本操作 和 Path之貝塞爾曲線 的講解,本篇終於進入Path的收尾篇,本篇結束後Path的大部分相關方法都已經講解完了,但Path還有一些更有意思的玩法,應該會在後續的文章中出現吧,嗯,應該會的ˊ_>ˋ
一.Path常用方法表
為了相容性 相關推薦
安卓自定義View進階: 圖片文字
安卓自定義View進階-Canvas之圖片文字
安卓自定義View進階-手勢檢測(GestureDecetor)
安卓自定義View進階-多點觸控詳解
安卓自定義View進階-特殊控制元件的事件處理方案
安卓自定義View進階-MotionEvent詳解
安卓自定義View進階-事件分發機制詳解
安卓自定義View進階-Matrix Camera
安卓自定義View進階-Matrix詳解
安卓自定義View進階-Matrix原理
安卓自定義View進階-PathMeasure
安卓自定義View進階-Path之貝塞爾曲線
安卓自定義View進階-Path之基本操作
安卓自定義View進階-分類與流程
安卓自定義View進階-Path之完結篇
安卓自定義View進階-縮放手勢檢測(ScaleGestureDecetor)
安卓自定義View進階-Canvas之畫布操作
安卓自定義 View 進階:貝塞爾曲線
安卓自定義View進階:Path基本操作
安卓自定義 View 進階:Path 完結篇(偽)