onMeasure пользовательский вид пояснения
Я попытался выполнить пользовательский компонент. Я расширил class View
и сделаю некоторый рисунок в onDraw
. Почему мне нужно переопределить onMeasure
? Если бы я этого не сделал, все было бы правильно. Может кто-нибудь объяснить это? Как написать мой метод onMeasure
? Я видел пару учебников, но каждый из них немного отличается от другого. Иногда они называют super.onMeasure
в конце, иногда они используют setMeasuredDimension
и не называют это. Где разница?
В конце концов, я хочу использовать несколько точно таких же компонентов. Я добавил эти компоненты в свой XML
файл, но я не знаю, насколько они велики. Я хочу установить его положение и размер позже (почему мне нужно установить размер в onMeasure
если в onDraw
когда я его рисую, также работает) в пользовательском classе компонента. Когда мне это нужно?
- Элемент списка списка проведите пальцем влево и проведите пальцем вправо?
- setEmptyView в ListView не показывает его вид в приложении для Android?
- ListView пуст при использовании функции getFilter
- Как нажимать или нажимать текст TextView на разные слова?
- ASP.NET MVC - просмотр с несколькими моделями
- Цвет текста в ListView Android
- OnItemClickListener и OnClickListener не работают в ListView
- Как обновить список просмотров Android?
- Android ListView setSelection (), похоже, не работает
- Элемент списка ListView с помощью настраиваемого селектора
- Android: использование WebView вне контекста активности
- ListView с OnItemClickListener android
- Android: переключения экранов с новой активностью или просто изменение содержимого
onMeasure()
– это ваша возможность рассказать Android о том, насколько вы хотите, чтобы ваше пользовательское представление зависело от ограничений макета, предоставляемых родителем; это также возможность вашего пользовательского представления узнать, что такое ограничения макета (в случае, если вы хотите вести себя по-разному в ситуации match_parent
чем в ситуации wrap_content
). Эти ограничения упаковываются в значения MeasureSpec
, которые передаются в этот метод. Вот грубая корреляция значений режима:
- ТОЧНО означает, что значение
layout_width
илиlayout_height
установлено на определенное значение. Вероятно, вы должны сделать свой вид такого размера. Это также может срабатывать при использованииmatch_parent
, чтобы установить размер точно в родительский вид (это зависит от макета в структуре). - AT_MOST обычно означает, что для параметра
layout_width
илиlayout_height
установлено значениеmatch_parent
илиwrap_content
где требуется максимальный размер (это зависит от макета в структуре), а размер родительского измерения – это значение. Вы не должны быть больше этого размера. - UNSPECIFIED обычно означает, что для параметра
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
- UNSPECIFIED никогда не запускается
В случае горизонтальной прокрутки ваш код будет работать.