android中onMeasure初看,深入理解佈局之一!
原文地址:http://my.oschina.net/banxi/blog/51247
今天學習android自定義元件:docs/guide/topics/ui/custom-components.html
其中有兩個對佈局介面影響很的方法,onDraw(),和onMeasure().
onDraw()比較好理解.onMeasure()就比較難理解一些,也更復雜些 ,引用文件中的說法就是:
onMeasure() is a little more involved.其實還有另一個方面的原因就是我對這個單詞measure不是很知道,然後果了下詞典,就放了下心,確實是測量的意思.
實現onMeasure()方法基本需要完成下面三個方面的事情(最終結果是你自己寫相應程式碼得出測量值並呼叫view的一個方法進行設定,告訴給你的view安排位置大小的父容器你要多大的空間.):
1.傳遞進來的引數,widthMeasureSpec,和heightMeasureSpec是你對你應該得出來的測量值的限制.
The overidden onMeasure() method is called with width and height measure specifications(widthMeasureSpec and heightMeasureSpec parameters,both are integer codes representing dimensions) which should be treated as requirements for the restrictions on the width and height measurements you should produce.
2. 你在onMeasure計算出來設定的width和height將被用來渲染元件.應當儘量在傳遞進來的width和height 宣告之間.
雖然你也可以選擇你設定的尺寸超過傳遞進來的宣告.但是這樣的話,父容器可以選擇,如clipping,scrolling,或者丟擲異常,或者(也許是用新的宣告引數)再次呼叫onMeasure()
Your component's onMeasure() method should calculate a measurement width and height which will be required to render the component.it should try to stay within the specified passed in.although it can choose to exceed them(in this case,the parent can choose what to do,including clipping,scrolling,throwing an excption,or asking the onMeasure to try again,perhaps with different measurement specifications).
3.一但width和height計算好了,就應該呼叫View.setMeasuredDimension(int width,int height)方法,否則將導致丟擲異常.
Once the width and height are calculated,the setMeasureDimension(int width,int height) method must be called with the calculated measurements.Failure to do this will result in an exceptiion being thrown
在Android提提供的一個自定義View示例中(在API demos 中的 view/LabelView)可以看到一個重寫onMeasure()方法的
例項,也比較好理解.
01 |
/** |
02 |
* @see android.view.View#measure(int, int) |
03 |
*/ |
04 |
@Override |
05 |
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec)
{ |
06 |
setMeasuredDimension(measureWidth(widthMeasureSpec), |
07 |
measureHeight(heightMeasureSpec)); |
08 |
} |
09 |
10 |
/** |
11 |
* Determines the width of this view |
12 |
* @param measureSpec A measureSpec packed into an int |
13 |
* @return The width of the view, honoring constraints from measureSpec |
14 |
*/ |
15 |
private int measureWidth( int measureSpec) { |
16 |
int result = 0 ; |
17 |
int specMode = MeasureSpec.getMode(measureSpec); |
18 |
int specSize = MeasureSpec.getSize(measureSpec); |
19 |
20 |
if (specMode == MeasureSpec.EXACTLY) { |
21 |
// We were told how big to be |
22 |
result = specSize; |
23 |
} else { |
24 |
// Measure the text |
25 |
result = ( int ) mTextPaint.measureText(mText) + getPaddingLeft() |
26 |
+ getPaddingRight(); |
27 |
if (specMode == MeasureSpec.AT_MOST) { |
28 |
// Respect AT_MOST value if that was what is called for by measureSpec |
29 |
result = Math.min(result, specSize); |
30 |
} |
31 |
} |
32 |
33 |
return result; |
34 |
} |
直接看measureWidth()
首先看到的是引數,分別代表寬度和高度的MeasureSpec
android2.2文件中對於MeasureSpec中的說明是:
一個MeasureSpec封裝了從父容器傳遞給子容器的佈局需求.
每一個MeasureSpec代表了一個寬度,或者高度的說明.
一個MeasureSpec是一個大小跟模式的組合值.一共有三種模式.
A MeasureSpec encapsulates the layout requirements passed from parent to child Each MeasureSpec represents a requirement for either the width or the height.A MeasureSpec is compsized of a size and a mode.There are three possible modes:
(1)UPSPECIFIED :父容器對於子容器沒有任何限制,子容器想要多大就多大.
UNSPECIFIED The parent has not imposed any constraint on the child.It can be whatever size it wants
(2) EXACTLY
父容器已經為子容器設定了尺寸,子容器應當服從這些邊界,不論子容器想要多大的空間.
EXACTLY The parent has determined and exact size for the child.The child is going to be given those bounds regardless of how big it wants to be.
(3) AT_MOST
子容器可以是宣告大小內的任意大小.
AT_MOST The child can be as large as it wants up to the specified size
MeasureSpec是View類下的靜態公開類,MeasureSpec中的值作為一個整型是為了減少物件的分配開支.此類用於
將size和mode打包或者解包為一個整型.
MeasureSpecs are implemented as ints to reduce object allocation.This class is provided to pack and unpack the size,mode tuple into the int
我比較好奇的是怎麼樣將兩個值打包到一個int中,又如何解包.
MeasureSpec類程式碼如下 :(註釋已經被我刪除了,因為在上面說明了.)
01 |
public static class MeasureSpec { |
02 |
private static final int MODE_SHIFT = 30 ; |
03 |
private static final int MODE_MASK = 0x3 <<
MODE_SHIFT; |
04 |
05 |
public static final int UNSPECIFIED = 0 <<
MODE_SHIFT; |
06 |
public static final int EXACTLY = 1 <<
MODE_SHIFT; |
07 |
public static final int AT_MOST = 2 <<
MODE_SHIFT; |
08 |
09 |
public static int makeMeasureSpec( int size, int mode)
{ |
10 |
return size + mode; |
11 |
} |
12 |
public static int getMode( int measureSpec)
{ |
13 |
return (measureSpec & MODE_MASK); |
14 |
} |
15 |
public static int getSize( int measureSpec)
{ |
16 |
return (measureSpec & ~MODE_MASK); |
17 |
} } |
我無聊的將他們的十進位制值列印出來了:
mode_shift=30,mode_mask=-1073741824,UNSPECIFIED=0,EXACTLY=1073741824,AT_MOST=-2147483648
然後覺得也應該將他們的二進位制值列印出來,如下:
mode_shift=11110, // 30
mode_mask=11000000000000000000000000000000,
UNSPECIFIED=0,
EXACTLY=1000000000000000000000000000000,
AT_MOST=10000000000000000000000000000000
1 |
MODE_MASK = 0x3 << MODE_SHIFT //也就是說MODE_MASK是由11左移30位得到的.因為Java用補碼錶示數值.最後得到的值最高位是1所以就是負數了 |
1 |
而把MODE_SHIFF就看成30.那為什麼是二進位制 的11呢?
呢,因為只有三各模式,如果有四種模式就是111了因為111三個位才可以有四種組合對吧.
我們這樣來看,
UNSPECIFIED=00000000000000000000000000000000,
EXACTLY=01000000000000000000000000000000,
AT_MOST=10000000000000000000000000000000
也就是說,0,1,2
對應 00,01,10
當跟11想與時 00 &11 還是得到 00,11&01 -> 01,10&
我覺得到了這個份上相信,看我部落格的也都理解了.
return (measureSpec & ~MODE_MASK);應該是 return (measureSpec & (~MODE_MASK));
相關文章
- 深入理解聖盃佈局和雙飛翼佈局
- 【譯】Flutter | 深入理解佈局約束Flutter
- Android中佈局的優化Android優化
- Android 佈局Android
- Android學習—— Android佈局Android
- 深入淺出grid佈局
- Android 佈局優化Android優化
- android --巧用 flexboxLayout 佈局AndroidFlex
- 深入理解 Python 的物件複製和記憶體佈局Python物件記憶體
- Android中常見的佈局和佈局引數Android
- 深入理解 Android 中的各種 ContextAndroidContext
- 初窺響應式佈局
- 簡單理解flex佈局Flex
- 理解 CSS 佈局和 BFCCSS
- Android FlexboxLayout 佈局詳解AndroidFlex
- Android入門教程 | UI佈局之LinearLayout 線性佈局AndroidUI
- Android入門教程 | UI佈局之RelativeLayout 相對佈局AndroidUI
- Flutter之在Flutter佈局中嵌入原生元件Android篇Flutter元件Android
- Android中View的測量和佈局過程AndroidView
- 深入理解Java虛擬機器之JVM記憶體佈局篇Java虛擬機JVM記憶體
- 【譯】理解 CSS 佈局和 BFCCSS
- 你真的理解 flex 佈局嗎?Flex
- 寫給 Android 開發的小程式佈局指南,Flex 佈局!AndroidFlex
- 寫給自己看的 Flex 佈局Flex
- Android開發之常用佈局Android
- Android的四個基本佈局Android
- Android效能優——佈局優化Android優化
- Android XML佈局報錯:android/view/View$OnUnhandledKeyEventListenerAndroidXMLView
- Android 深入理解 Notification 機制Android
- Android 常用佈局 介紹與使用Android
- Android佈局優化三劍客Android優化
- 帶你深入理解Android中的自定義屬性!!!Android
- Android佈局中動態新增ImageView並設定間隔AndroidView
- Avalonia中的佈局
- 深入理解Java虛擬機器之物件的記憶體佈局、訪問定位Java虛擬機物件記憶體
- web 應用開發最佳實踐之一:避免大型、複雜的佈局和佈局抖動Web
- Android 中LayoutInflater(佈局載入器)原始碼篇之rInflate方法Android原始碼
- 深入理解Android訊息機制Android
- 深入理解Android逆向除錯原理Android除錯