自定義View之onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法解釋
Android中的控制元件都是View或者View的子類,因此一個自定義View可以直接繼承自View或者View的子類。
當現有控制元件不能滿足我們的要求時,我們需要自己動手畫出我們想要的View。
如何去畫呢?
首先我們知道一個View的生成需要經過測量、佈局和繪製三步,分別對應View中的 onMeasure()、onLayout()和onDraw()方法。
onMeasure()方法
該方法用來測量需要繪製的View的大小,即告訴系統我有多大,系統呼叫時傳入兩個引數widthMeasureSpec和heightMeasureSpec。首先這兩個引數是由這個View的具體的ViewGroup呼叫的,
它由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同決定。權值weight也是尤其需要考慮的因素,有它的存在情況可能會稍微複雜點。
兩個引數基本類似,取其一說明:
widthMeasureSpec這個值由高32位和低16位組成,高32位儲存的值叫specMode,可以通過如程式碼中所示的MeasureSpec.getMode()獲取;低16位為specSize,同樣可以由MeasureSpec.getSize()獲取。那麼specMode和specSize的作用有是什麼呢?要想知道這一點,我們需要知道程式碼中的最後一行,所有的View的onMeasure()的最後一行都會呼叫setMeasureDimension()函式的作用——這個函式呼叫中傳進去的值是View最終的檢視大小。也就是說onMeasure()中之前所作的所有工作都是為了最後這一句話服務的。
在ViewGroup中,給View分配的空間大小並不是確定的,有可能隨著具體的變化而變化,而這個變化的條件就是傳到specMode中決定的,specMode一共有三種可能:
MeasureSpec.EXACTLY:父檢視希望子檢視的大小應該是specSize中指定的。
MeasureSpec.AT_MOST:子檢視的大小最多是specSize中指定的值,也就是說不建議子檢視的大小超過specSize中給定的值。
MeasureSpec.UNSPECIFIED:我們可以隨意指定檢視的大小。
因此我們知道這個值的設計意義是為了根據ViewGroup中具體能夠提供的空間大小來指定子View的檢視大小。而檢視最終的大小由父檢視,子檢視以及程式設計師根據需要決定,良好的設計一般會根據子檢視的measureSpec設定合適的佈局大小。
下面給出自己的一個onMeasure()方法計算的實現:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//根據提供的測量值提取模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
//根據提供的測量值提取大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
/**依據得到的specMode值,如果是AT_MOST,specSize 代表的是最大可獲得的空間;如果EXACTLY, specSize 代表的是精確的尺寸;如果是UNSPECIFIED,對於控制元件尺寸來說,沒有任何參考意義。當以EXACT方式標記測量尺寸,父元素會堅持在一個指定的精確尺寸區域放置View。在父元素問子元素要多大空間時,AT_MOST指示者會說給我最大的範圍。在很多情況下,你得到的值都是相同的。在兩種情況下,你必須絕對的處理這些限制。在一些情況下,它可能會返回超出這些限制的尺寸,在這種情況下,你可以讓父元素選擇如何對待超出的View,使用裁剪還是滾動等技術。**/
if(widthMode == MeasureSpec.EXACTLY){
//不需要重新計算
widthMeasureSpec = widthSize;
}else {
//重新計算,這裡計算你需要繪製的檢視的寬
widthMeasureSpec = getPaddingLeft()+getPaddingRight()+rect.width();
}
if(heightMode == MeasureSpec.EXACTLY){
heightMeasureSpec = heightSize;
}else {
heightMeasureSpec = getPaddingTop()+getPaddingBottom()+rect.height();
}
//然後呼叫自setMeasuredDimension()方法將測量好的寬高儲存
setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
}
好了,onMeasure()方法就介紹到這裡了!
**
重點內容**# 歡迎使用Markdown編輯器寫部落格
本Markdown編輯器使用StackEdit修改而來,用它寫部落格,將會帶來全新的體驗哦:
- Markdown和擴充套件Markdown簡潔的語法
- 程式碼塊高亮
- 圖片連結和圖片上傳
- LaTex數學公式
- UML序列圖和流程圖
- 離線寫部落格
- 匯入匯出Markdown檔案
- 豐富的快捷鍵
快捷鍵
- 加粗
Ctrl + B
- 斜體
Ctrl + I
- 引用
Ctrl + Q
- 插入連結
Ctrl + L
- 插入程式碼
Ctrl + K
- 插入圖片
Ctrl + G
- 提升標題
Ctrl + H
- 有序列表
Ctrl + O
- 無序列表
Ctrl + U
- 橫線
Ctrl + R
- 撤銷
Ctrl + Z
- 重做
Ctrl + Y
Markdown及擴充套件
Markdown 是一種輕量級標記語言,它允許人們使用易讀易寫的純文字格式編寫文件,然後轉換成格式豐富的HTML頁面。 —— [ 維基百科 ]
使用簡單的符號標識不同的標題,將某些文字標記為粗體或者斜體,建立一個連結等,詳細語法參考幫助?。
本編輯器支援 Markdown Extra , 擴充套件了很多好用的功能。具體請參考Github.
表格
Markdown Extra 表格語法:
專案 | 價格 |
---|---|
Computer | $1600 |
Phone | $12 |
Pipe | $1 |
可以使用冒號來定義對齊方式:
專案 | 價格 | 數量 |
---|---|---|
Computer | 1600 元 | 5 |
Phone | 12 元 | 12 |
Pipe | 1 元 | 234 |
定義列表
- Markdown Extra 定義列表語法:
- 專案1
- 專案2
- 定義 A
- 定義 B
- 專案3
- 定義 C
-
定義 D
定義D內容
程式碼塊
程式碼塊語法遵循標準markdown程式碼,例如:
@requires_authorization
def somefunc(param1='', param2=0):
'''A docstring'''
if param1 > param2: # interesting
print 'Greater'
return (param2 - param1 + 1) or None
class SomeClass:
pass
>>> message = '''interpreter
... prompt'''
腳註
生成一個腳註1.
目錄
用 [TOC]
來生成目錄:
數學公式
- 行內公式,數學公式為:
Γ(n)=(n−1)!∀n∈N 。 - 塊級公式:
更多LaTex語法請參考 這兒.
UML 圖:
可以渲染序列圖:
或者流程圖:
離線寫部落格
即使使用者在沒有網路的情況下,也可以通過本編輯器離線寫部落格(直接在曾經使用過的瀏覽器中輸入write.blog.csdn.net/mdeditor即可。Markdown編輯器使用瀏覽器離線儲存將內容儲存在本地。
使用者寫部落格的過程中,內容實時儲存在瀏覽器快取中,在使用者關閉瀏覽器或者其它異常情況下,內容不會丟失。使用者再次開啟瀏覽器時,會顯示上次使用者正在編輯的沒有發表的內容。
部落格發表後,本地快取將被刪除。
使用者可以選擇 把正在寫的部落格儲存到伺服器草稿箱,即使換瀏覽器或者清除快取,內容也不會丟失。
注意:雖然瀏覽器儲存大部分時候都比較可靠,但為了您的資料安全,在聯網後,請務必及時發表或者儲存到伺服器草稿箱。
瀏覽器相容
- 目前,本編輯器對Chrome瀏覽器支援最為完整。建議大家使用較新版本的Chrome。
- IE9以下不支援
- IE9,10,11存在以下問題
- 不支援離線功能
- IE9不支援檔案匯入匯出
- IE10不支援拖拽檔案匯入
- 這裡是 腳註 的 內容. ↩