Основная проблема заключается в том, что вам нужно дождаться фазы рисования для фактических измерений (особенно с динамическими значениями, такими как wrap_content
или match_parent
), но обычно эта фаза не завершена onResume()
. Так что вам нужен обходной путь для ожидания этого этапа. Существуют различные возможные решения этого:
1. Прослушивание событий Draw / Layout: ViewTreeObserver
ViewTreeObserver запускается для различных событий рисования. Обычно OnGlobalLayoutListener
это то, что вы хотите получить для измерения, поэтому код в слушателе будет вызываться после фазы компоновки, поэтому измерения готовы:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Примечание. Слушатель будет немедленно удален, поскольку в противном случае он будет срабатывать при каждом событии макета. Если вам нужно поддерживать приложения SDK Lvl <16, используйте это, чтобы отменить регистрацию слушателя:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Добавьте исполняемый файл в очередь макетов: View.post ()
Не очень известное и мое любимое решение. По сути, просто используйте метод post представления View с вашим собственным runnable. Это в основном ставит ваш код в очередь после измерения представления, макета и т. Д., Как заявлено Romain Guy :
Очередь событий пользовательского интерфейса будет обрабатывать события по порядку. После вызова setContentView () очередь событий будет содержать сообщение с просьбой о ретрансляции, поэтому все, что вы отправляете в очередь, произойдет после передачи макета
Пример:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Преимущество перед ViewTreeObserver
:
- Ваш код выполняется только один раз, и вам не нужно отключать Observer после выполнения, что может быть хлопотно
- менее подробный синтаксис
Ссылки:
3. Перезаписать метод onLayout в представлениях
Это практично только в определенных ситуациях, когда логика может быть заключена в самом представлении, в противном случае это довольно многословный и громоздкий синтаксис.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
Также учтите, что onLayout будет вызываться много раз, поэтому будьте внимательны, что вы делаете в методе, или отключите свой код после первого раза.
4. Проверьте, прошел ли этап макета
Если у вас есть код, который выполняется несколько раз при создании пользовательского интерфейса, вы можете использовать следующий метод поддержки v4 lib:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Возвращает true, если представление было выполнено хотя бы через один макет с момента последнего присоединения к окну или отсоединения от него.
Дополнительно: получение статически определенных измерений
Если достаточно просто получить статически определенную высоту / ширину, вы можете сделать это с помощью:
Но учтите, что это может отличаться от фактической ширины / высоты после рисования. Javadoc отлично описывает разницу:
Размер представления выражается шириной и высотой. Вид фактически обладает двумя парами значений ширины и высоты.
Первая пара известна как измеренная ширина и измеренная высота. Эти измерения определяют, насколько большим должно быть представление в пределах его родителя (см. Layout для более подробной информации.) Измеренные измерения можно получить, вызвав getMeasuredWidth () и getMeasuredHeight ().
Вторая пара просто называется шириной и высотой, а иногда шириной и высотой рисования. Эти размеры определяют фактический размер вида на экране, во время рисования и после макета. Эти значения могут, но не обязательно, отличаться от измеренной ширины и высоты. Ширина и высота могут быть получены путем вызова getWidth () и getHeight ().