除非你總是需要一個100×100像素的控件,否則,你必須要重寫onMeasure。
onMeasure方法在控件的父元素正要放置它的子控件時調用。它會問一個問題,“你想要用多大地方啊?”,然後傳入兩個參數——
widthMeasureSpec和heightMeasureSpec。它們指明控件可獲得的空間以及關於這個空間描述的元數據。
比返回一個結果要好的方法是你傳遞View的高度和寬度到setMeasuredDimension方法裏。
接下來的代碼片段給出瞭如何重寫onMeasure。注意,調用的本地空方法是來計算高度和寬度的。它們會譯解widthHeightSpec和heightMeasureSpec值,並計算出合適的高度和寬度值。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
setMeasuredDimension(measuredHeight, measuredWidth);
}
private int measureHeight(int measureSpec) {
// Return measured widget height.
}
private int measureWidth(int measureSpec) {
// Return measured widget width.
}
邊界參數——widthMeasureSpec和heightMeasureSpec ,效率的原因以整數的方式傳入。在它們使用之前,首先要做的是使用MeasureSpec類的靜態方法getMode和getSize來譯解,如下面的片段所示:
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
依據specMode的值,如果是AT_MOST,specSize 代表的是最大可獲得的空間;如果是EXACTLY,specSize 代表的是精確的尺寸;如果是UNSPECIFIED,對於控件尺寸來說,沒有任何參考意義。
當以EXACT方式標記測量尺寸,父元素會堅持在一個指定的精確尺寸區域放置View。在父元素問子元素要多大空間時,AT_MOST指示者會說給我最大的範圍。在很多情況下,你得到的值都是相同的。
在兩種情況下,你必須絕對的處理這些限制。在一些情況下,它可能會返回超出這些限制的尺寸,在這種情況下,你可以讓父元素選擇如何對待超出的View,使用裁剪還是滾動等技術。
接下來的框架代碼給出了處理View測量的典型實現:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
setMeasuredDimension(measuredHeight, measuredWidth);
}
private int measureHeight(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST)
{
// Calculate the ideal size of your
// control within this maximum size.
// If your control fills the available
// space return the outer bound.
result = specSize;
}
else if (specMode == MeasureSpec.EXACTLY)
{
// If your control can fit within these bounds return that value.
result = specSize;
}
return result;
}
private int measureWidth(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
int result = 500;
if (specMode == MeasureSpec.AT_MOST)
{
// Calculate the ideal size of your control
// within this maximum size.
// If your control fills the available space
// return the outer bound.
result = specSize;
}
else if (specMode == MeasureSpec.EXACTLY)
{
// If your control can fit within these bounds return that value.
result = specSize;
}
return result;
}