Ответ 1
onMeasure()
- это ваша возможность рассказать Android о том, насколько вы хотите, чтобы ваш пользовательский вид зависел от ограничений макета, предоставляемых родителем; вы также можете узнать, что такое ограничения компоновки (если вы хотите вести себя по-разному в ситуации match_parent
, чем в ситуации wrap_content
). Эти ограничения упаковываются в значения MeasureSpec
, которые передаются в этот метод. Вот грубая корреляция значений режима:
- ТОЧНО означает, что значение
layout_width
илиlayout_height
установлено на определенное значение. Вероятно, вы должны сделать свой вид такого размера. Это также может срабатывать, когда используетсяmatch_parent
, чтобы установить размер точно в родительский вид (это зависит от макета в структуре). - AT_MOST обычно означает, что для параметра
layout_width
илиlayout_height
установлено значениеmatch_parent
илиwrap_content
, где требуется максимальный размер (это зависит от компоновки в структуре), и размер родительского измерения - это значение. Вы не должны быть больше этого размера. - НЕСООТВЕТСТВУЕТ, как правило, значение
layout_width
илиlayout_height
установлено наwrap_content
без ограничений. Вы можете быть в любом размере. Некоторые макеты также используют этот обратный вызов, чтобы определить желаемый размер, прежде чем определять, какие спецификации фактически передадут вам снова во втором запросе измерения.
Контракт, который существует с onMeasure()
, заключается в том, что в конце будет вызываться setMeasuredDimension()
MUST с размером, которым вы хотели бы видеть. Этот метод вызывается всеми реализациями фреймворка, включая реализацию по умолчанию, найденную в View
, поэтому безопасно вызывать super
, если это соответствует вашему прецеденту.
Предположим, что, поскольку инфраструктура применяет реализацию по умолчанию, вам может не понадобиться переопределять этот метод, но вы можете увидеть обрезание в случаях, когда пространство просмотра меньше вашего содержимого, если вы этого не сделаете, и если вы выложите свой пользовательский вид с помощью wrap_content
в обоих направлениях, ваше представление может вообще не отображаться, потому что фреймворк не знает, насколько он большой!
Как правило, если вы переопределяете View
, а не другой существующий виджет, вероятно, хорошая идея обеспечить реализацию, даже если это так просто, как что-то вроде этого:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
}
Надеюсь, что это поможет.