Как вы можете определить, когда был составлен макет?
У меня есть пользовательский вид, который рисует прокручиваемое растровое изображение на экране. Чтобы инициализировать его, мне нужно передать размер в пикселях родительского объекта макета. Но во время функций onCreate и onResume макет еще не нарисован, и поэтому layout.getMeasuredHeight() возвращает 0.
В качестве обходного пути я добавил обработчик, чтобы подождать одну секунду, а затем измерить. Это работает, но его неряшливо, и я понятия не имею, насколько я могу сократить время до того, как я закончу до того, как макет нарисован.
Что я хочу знать, как определить, когда макет нарисован? Есть ли событие или обратный вызов?
Ответы
Ответ 1
Вы можете добавить дерево наблюдателя к макету. Это должно вернуть правильную ширину и высоту. onCreate()
вызывается перед созданием дочерних представлений. Так что ширина и высота еще не рассчитаны. Чтобы получить высоту и ширину, поместите это в метод onCreate()
:
final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
layout.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
layout.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
Ответ 2
Самый простой способ - просто называть post()
на вашем макете. Это запустит ваш код следующим шагом после того, как ваше представление уже создано.
YOUR_LAYOUT.post( new Runnable() {
@Override
public void run() {
int width = YOUR_LAYOUT.getMeasuredWidth();
int height = YOUR_LAYOUT.getMeasuredHeight();
}
});
Ответ 3
Чтобы избежать устаревшего кода и предупреждений, вы можете использовать:
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
view.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
yourFunctionHere();
}
});
Ответ 4
Другой ответ:
Попробуйте проверить размеры View в onWindowFocusChanged
.
Ответ 5
Альтернативой обычным методам является подключение к чертежу вида.
OnPreDrawListener
вызывается много раз при отображении представления, поэтому не существует конкретной итерации, где у вашего представления есть допустимая измеренная ширина или высота. Это требует, чтобы вы постоянно view.getMeasuredWidth() <= 0
(view.getMeasuredWidth() <= 0
) или устанавливали ограничение на количество проверок для measuredWidth
ширины больше нуля.
Существует также вероятность того, что представление никогда не будет отображено, что может указывать на другие проблемы с вашим кодом.
final View view = [ACQUIRE REFERENCE]; // Must be declared final for inner class
ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (view.getMeasuredWidth() > 0) {
view.getViewTreeObserver().removeOnPreDrawListener(this);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
//Do something with width and height here!
}
return true; // Continue with the draw pass, as not to stop it
}
});
Ответ 6
Просто проверьте это, вызвав метод post на вашем макете или представлении
view.post( new Runnable() {
@Override
public void run() {
// your layout is now drawn completely , use it here.
}
});
Ответ 7
Когда onMeasure
, представление получает измеренную ширину/высоту. После этого вы можете вызвать layout.getMeasuredHeight()
.
Ответ 8
Лучше с функциями расширения kotlin
inline fun View.waitForLayout(crossinline yourAction: () -> Unit) {
val vto = viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
when {
vto.isAlive -> {
vto.removeOnGlobalLayoutListener(this)
yourAction()
}
else -> viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}
})
}