объяснение пользовательского представления onMeasure
Я пытался сделать пользовательский компонент. Я продлил View
класс и сделать некоторые чертежи в onDraw
способ перекрытая. Почему мне нужно переопределить onMeasure
? Если бы я этого не сделал, все было бы правильно. Может кто-нибудь объяснить это? Как я должен написать мой onMeasure
способ? Я видел пару учебников, но каждый из них немного отличается от другого. Иногда они называют super.onMeasure
в конце концов, иногда они используют setMeasuredDimension
и не назвал его. В чем же разница?
ведь я хочу использовать несколько точно таких же компонентов. Я добавил Эти компоненты в мой XML
файл, но я не знаю, насколько они должны быть большими. Я хочу установить его положение и размер позже (почему мне нужно установить размер в onMeasure
Если в onDraw
когда я его рисую, тоже работает) в классе пользовательских компонентов. Когда именно мне нужно это сделать?
2 ответа:
onMeasure()
это ваша возможность сказать Android, насколько большой вы хотите, чтобы ваш пользовательский вид зависел от ограничений макета, предоставленных родителем; это также возможность вашего пользовательского представления узнать, каковы эти ограничения макета (в случае, если вы хотите вести себя по-другому вmatch_parent
ситуация, чем awrap_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()
должны вызывается в конце с размером, который вы хотели бы видеть. Этот метод вызывается всеми реализациями платформы, включая реализацию по умолчанию, найденную в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); }
надеюсь, что это поможет.
на самом деле, ваш ответ не полный, так как значения также зависят от упаковка контейнер. В случае относительных или линейных макетов значения ведут себя следующим образом:
- ровно match_parent точно + размер родителя
- AT_MOST результаты wrap_content в качестве параметров в AT_MOST MeasureSpec
- не указано не запускается
в случае горизонтальной прокрутки, ваш код будет работа.