Основная проблема заключается в том, что вам нужно дождаться фазы рисования для фактических измерений (особенно с динамическими значениями, такими как 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 </em>, используйте это, чтобы отменить регистрацию слушателя:
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 отлично описывает разницу:
Размер представления выражается шириной и высотой. Вид
на самом деле обладают двумя парами значений ширины и высоты.
Первая пара известна как измеренная ширина и измеренная высота. Эти
Размеры определяют, насколько большим должно быть представление в пределах своего родителя (см.
План для более подробной информации.) Измеренные размеры могут быть получены путем
вызов getMeasuredWidth () и getMeasuredHeight ().
Вторая пара просто называется шириной и высотой, а иногда
ширина рисунка и высота рисунка. Эти размеры определяют фактическое
размер вида на экране, во время рисования и после макета. Эти
значения могут отличаться от измеренной ширины, но не обязательно
и высота. Ширина и высота могут быть получены с помощью вызова getWidth ()
и getHeight ().