Получить фактическую высоту обзора

Простой вопрос, возможно, удручающе сложный, но, надеюсь, простой ответ?

Какова «лучшая практика» для получения фактической высоты элемента, для которого установлен размер FILL_PARENT?


person Wonko the Sane    schedule 21.12.2010    source источник
comment
Вероятно, это дубликат этого вопроса SO: заголовок stackoverflow.com/questions/2864331/   -  person Yoni Samlan    schedule 21.12.2010
comment
Спасибо - мой поиск фу уже ушел на праздник. Я собираюсь сначала попробовать ответ ниже, но хорошо иметь варианты.   -  person Wonko the Sane    schedule 21.12.2010


Ответы (2)


Определенно сложнее, чем кажется. Более простой способ, который я нашел по сравнению с ответом на предложенный вопрос, - использовать ViewTreeObserver. В вашем методе onCreate() вы можете использовать следующий код:

TextView textView = (TextView)findViewById(R.id.my_textview);
ViewTreeObserver observer = textView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        //in here, place the code that requires you to know the dimensions.
        //this will be called as the layout is finished, prior to displaying.
    }
});
person Kevin Coppock    schedule 21.12.2010
comment
У меня работает - спасибо. Единственное предостережение заключается в том, что вам нужно позаботиться о том, чтобы уловить тот факт, что вы вошли в событие один раз (или только по мере необходимости), иначе вы окажетесь в бесконечном цикле макета. - person Wonko the Sane; 21.12.2010
comment
Не могли бы вы подробнее объяснить, что вы имеете в виду? Я не совсем понимаю. Разве он не будет вызываться только во время onCreate() или onResume() один раз? - person Kevin Coppock; 21.12.2010
comment
(Извините за задержку - рождественские каникулы) Нет - вы создаете обработчик событий, поэтому он будет вызываться при каждом изменении макета. Если у вас нет флага, который говорит, что я внес необходимые изменения в макет, он вызовет его снова, когда вы внесли свое изменение, и снова после того, как это изменение будет сделано, и... - person Wonko the Sane; 28.12.2010
comment
Значит, вы попали бы в цикл только в том случае, если бы вы действительно изменили что-то в макете? Таким образом, вы могли бы изменить onGlobalLayout другую переменную, а затем просто удалить OnGlobalLayoutListener? (Интересное примечание: в документации ViewTreeObserver метод для удаления кажется ошибочно названным removeGlobalOnLayoutListener вместо removeOnGlobalLayoutListener.) - person Kevin Coppock; 28.12.2010
comment
@kcoppock оба метода существуют, но один устарел, а другой недоступен до API 16. Похоже, они решили изменить имя метода... developer.android.com/reference/android/view/ - person Andrew Wyld; 01.03.2013
comment
О, подождите, я только что понял, что вы, вероятно, написали это до API 16. Что ж, теперь существуют оба метода! Думаю, они заметили несоответствие между API и документацией и решили, что API неправильный! - person Andrew Wyld; 01.03.2013
comment
@AndrewWyld Ха-ха, да, я почти хотел бы, чтобы они этого не сделали; теперь мы должны иметь дело с предупреждением об устаревании, когда мы его используем. ›.› - person Kevin Coppock; 01.03.2013

Просто дополнительная поправка к приведенному выше ответу, если вам нужно выполнить какие-либо операции с размерами нескольких компонентов в представлении. Слушатель компоновки вызывается для каждого представления по мере завершения компоновки. Это рекурсивно верно для корневого компонента представления (т. е. дочерние элементы генерируют события макета, затем родительский элемент генерирует свое событие макета). Это означает, что вы можете просто подключиться к событию макета корневого компонента представления, чтобы получать уведомления при изменении макета любого представления.

ViewTreeObserver observer = this.findViewById(android.R.id.content).getViewTreeObserver();

Теперь вы можете ожидать, что все ваши представления будут иметь значения ширины и высоты, установленные в onGlobalLayout, потому что все они выполнили свой макет. Это, очевидно, предпочтительнее, чем создавать множество прослушивателей для каждого представления, которое должно отображать свои фактические размеры (если, конечно, вам абсолютно не нужна область действия, для которой представление сгенерировало событие, что обычно не требуется).

person pjs    schedule 23.09.2014
comment
Также убедитесь, что вы не измеряете размеры элементов в состоянии видимости = исчезновении. Или вы можете обнаружить, что рекурсивность не работает - person Nikolay R; 02.04.2015