Методы getWidth() и getHeight() у View возвращают 0
У меня такая проблема: я создаю все элементы динамически в своем проекте для Android. Я пытаюсь получить ширину и высоту кнопки, чтобы затем повернуть эту кнопку. Я только начинаю осваивать язык программирования для Android, но в результате получаю 0.
Я провел небольшое исследование и увидел, что это нужно делать не в методе onCreate(). Если кто-то сможет предоставить пример того, как это сделать, я был бы очень признателен.
Вот мой текущий код:
package com.animation;
import android.app.Activity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.LinearLayout;
public class AnimateScreen extends Activity {
// Вызывается при создании активности
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(30, 20, 30, 0);
Button bt = new Button(this);
bt.setText(String.valueOf(bt.getWidth()));
RotateAnimation ra = new RotateAnimation(0, 360, bt.getWidth() / 2, bt.getHeight() / 2);
ra.setDuration(3000L);
ra.setRepeatMode(Animation.RESTART);
ra.setRepeatCount(Animation.INFINITE);
ra.setInterpolator(new LinearInterpolator());
bt.startAnimation(ra);
ll.addView(bt, layoutParams);
setContentView(ll);
}
}
Помогите, пожалуйста, разобраться, как правильно получать размеры кнопки для вращения.
5 ответ(ов)
Чтобы получить размер окна в методе onWindowFocusChanged, вы можете использовать следующий код:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// Здесь вы можете получить размер!
}
В данном методе, когда ваше окно получает или теряет фокус, можно добавить логику для получения размеров окна. Например, вы можете использовать getWindow().getDecorView().getWidth() и getWindow().getDecorView().getHeight(), чтобы получить ширину и высоту окна соответственно. Однако, стоит учитывать, что этот метод вызывается каждый раз при изменении фокуса, так что убедитесь, что вы проверяете состояние hasFocus перед выполнением операции, если это необходимо.
Я использовал это решение, которое, на мой взгляд, лучше, чем onWindowFocusChanged(). Если открывается DialogFragment, то onWindowFocusChanged будет вызван только тогда, когда пользователь закроет диалог.
Вот код:
yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Убедитесь, что вызываете это только один раз:
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Здесь вы можете получить размер :)
}
});
Важно: так как метод removeGlobalOnLayoutListener устарел, теперь следует использовать следующий подход:
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Убедитесь, что вызываете это только один раз:
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// Здесь вы можете получить размер :)
}
Таким образом, код будет работать корректно на более новых версиях Android, и вы избежите использования устаревших методов.
Если вам нужно получить ширину какого-либо виджета до его отображения на экране, вы можете использовать методы getMeasuredWidth() и getMeasuredHeight().
Для этого необходимо вызвать метод measure() у вашего виджета, указав параметры WRAP_CONTENT для ширины и высоты. Вот пример кода:
myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();
Таким образом, после вызова measure() вы сможете получить размеры вашего виджета, даже если он еще не отображен на экране.
AndroidX предоставляет несколько функций-расширений, которые могут помочь вам с подобной задачей в androidx.core.view.
Вам необходимо использовать Kotlin для этого.
Функция, которая наилучшим образом подходит для вашего случая, — это doOnLayout:
Выполняет заданное действие, когда этот вид размечен. Если вид уже был размечен и не запросил новую разметку, действие будет выполнено немедленно. В противном случае действие будет выполнено после следующей разметки вида.
Действие будет вызвано только один раз на следующей разметке, а затем удалено.
В вашем примере это будет выглядеть так:
bt.doOnLayout {
val ra = RotateAnimation(0, 360, it.width / 2, it.height / 2)
// дополнительный код
}
Не забудьте добавить зависимость: androidx.core:core-ktx:1.0.0.
Вы можете создать расширение для Kotlin, которое будет отслеживать изменения глобального макета и выполнять заданную задачу, когда высота вью будет готова динамически. Это полезно, если вам нужно получить высоту вью после того, как макет был построен.
Использование:
view.height { Log.i("Info", "Вот ваша высота: $it") }
Реализация:
fun <T : View> T.height(function: (Int) -> Unit) {
if (height == 0) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
function(height)
}
})
} else {
function(height)
}
}
Объяснение:
- Функция расширения
heightпринимает лямбда-выражение, которое будет вызвано с высотой вью. - Если высота вью равна 0, это означает, что макет еще не был построен, и мы добавляем слушатель
OnGlobalLayoutListener. - В методе
onGlobalLayout, как только макет будет готов, слушатель удаляется и вызывается переданная функция с текущей высотой. - Если высота уже известна, функция вызывается немедленно.
Этот подход позволяет вам легко инициализировать действия, зависящие от высоты вью, без необходимости ручной обработки макета.
"Ошибка загрузки виджета"
Как вызвать метод с задержкой в Android
Использование контекста в фрагменте
Как проверить доступ к интернету на Android? InetAddress никогда не выдает таймаут
Room - Директория экспорта схемы не указана аннотационному процессору, не удается экспортировать схему