Основна проблема полягає в тому, що вам доведеться чекати фази креслення для фактичних вимірювань (особливо з такими динамічними значеннями, як wrap_content
або match_parent
), але зазвичай ця фаза ще не закінчена onResume()
. Тож вам потрібне вирішення для очікування цієї фази. Для цього є різні можливі рішення:
1. Прослуховуйте події малювання / макета: 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 ()
Не дуже відоме і моє улюблене рішення. В основному просто використовуйте метод публікації публікації з власним запуском. Це, в основному, черги з вашим кодом після вимірювання, компонування і т.д., як це заявив Ромен Гай :
Черга подій UI буде обробляти події в порядку. Після виклику setContentView () черга подій буде містити повідомлення із запитом про перенавантаження, тому все, що ви надсилаєте до черги, відбуватиметься після проходу макета
Приклад:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Перевага перед ViewTreeObserver
:
- ваш код виконується лише один раз, і вам не доведеться вимикати спостерігача після його виконання, що може скласти клопоти
- менш багатослівний синтаксис
Список літератури:
3. Перезапишіть метод onLayout Views
Це практично лише в певних ситуаціях, коли логіка може бути інкапсульована у самому погляді, інакше це досить багатослівний і громіздкий синтаксис.
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();
}
Повертає істину, якщо погляд пройшов принаймні один макет з моменту останнього прикріплення до вікна.
Додатково: отримання статично визначених вимірювань
Якщо досить просто отримати статично задану висоту / ширину, ви можете просто зробити це за допомогою:
Але зауважте, що після малювання це може відрізнятися від фактичної ширини / висоти. Явадок чудово описує різницю:
Розмір виду виражається шириною та висотою. Вид фактично має дві пари значень ширини та висоти.
Перша пара відома як вимірювана ширина і вимірювана висота. Ці параметри визначають, наскільки великий вигляд хоче бути у його батьківського (див. Макет для отримання більш детальної інформації.) Вимірені розміри можна отримати, викликавши getMeasuredWidth () та getMeasuredHeight ().
Друга пара просто відома як ширина та висота, а іноді ширина малювання та висота малюнка. Ці розміри визначають фактичний розмір зображення на екрані, під час малювання та після компонування. Ці значення можуть, але не повинні, відрізнятися від вимірюваної ширини та висоти. Ширину та висоту можна отримати, зателефонувавши getWidth () та getHeight ().