measure é usado para medir a largura e a altura da View. Seu processo é dividido em processo de medição de View e processo de medição de ViewGroup; mas o processo de medição de ViewGroup não apenas precisa concluir sua própria medição, mas também chama o método de medição de subelementos ergodicamente.
1. O processo de medição do View
Primeiro olhe para o método onMeasure da View:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
Vamos dar uma olhada no método setMeasuredDimension:
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
boolean optical = isLayoutModeOptical(this);
if (optical != isLayoutModeOptical(mParent)) {
Insets insets = getOpticalInsets();
int opticalWidth = insets.left + insets.right;
int opticalHeight = insets.top + insets.bottom;
measuredWidth += optical ? opticalWidth : -opticalWidth;
measuredHeight += optical ? opticalHeight : -opticalHeight;
}
setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}
Pode-se ver claramente que isso é usado para definir a largura e a altura da exibição. Vamos voltar e ver o que o método getDefaultSize manipula?
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
specMode é o modo de medição do View e specSize é o tamanho de medição do View. Aqui é óbvio que diferentes valores de resultado são retornados de acordo com diferentes valores de specMode. Isso é specSize. Nos modos AT_MOST (match_parent) e EXACTLY (wrapcontent, xx dp), o valor de specSize é retornado. Ou seja, a largura e a altura medidas de View nesses dois modos dependem de specSize. Ou seja, para uma View personalizada herdada diretamente da View, suas propriedades wrap_content e match_parent têm o mesmo efeito. Portanto, se você deseja implementar o wrap_content de uma View personalizada, você precisa substituir o método onMeasure e processar a propriedade wrap_content da View personalizada. No modo UNSPRECIFIED é retornado o valor do primeiro parâmetro tamanho do método getDefaultSize, e o valor do tamanho é obtido através do método sugeridoMiniumWidth ou método getSuggestMininumHeight do método onMesaure. Vamos ver o que o método getSuggestdMinumWidth faz:
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
Se a exibição não definir o plano de fundo, o valor será mMinWidth. Pode-se definir mMinWidth, que corresponde ao valor definido pela propriedade Android:minWidth. Ou o valor de setMinnumWidth of View; se não especificado, o padrão é 0.
O código para setMinumWidth é o seguinte:
public void setMinimumWidth(int minWidth) {
mMinWidth = minWidth;
requestLayout();
}
Se a Visualização definir o plano de fundo. O valor é max(mMinWidth, mBackgroud.getMinumWidth()), ou seja, o valor máximo entre mMinWidth e mBackgroud.getMinumWidth(). Vamos dar uma olhada em mBackgoud.getMininumWidth(). Este mBackgroud é do tipo Drawable, então vamos ver o método getMinumWidth da classe Drawable:
public int getMinimumWidth() {
final int intrinsicWidth = getIntrinsicWidth();
return intrinsicWidth > 0 ? intrinsicWidth : 0;
}
intrinsecamenteWidth obtém a largura intrínseca deste Drawable. Se esta largura intrínseca > 0, retorne a largura intrínseca, caso contrário, retorne 0. Resumindo, o método getSuggestedMininumWidth; se a View não definir o fundo, retorna mMinWidth; se o fundo estiver definido, retorna o valor máximo entre mMinWidth e a largura mínima do Drawable.