Estoy creando todos los elementos en mi proyecto de Android de forma dinámica. Estoy tratando de obtener el ancho y la altura de un botón para poder rotarlo. Solo estoy tratando de aprender a trabajar con el lenguaje Android. Sin embargo, devuelve 0.
Investigué un poco y vi que debe hacerse en otro lugar que no sea el onCreate()
método. Si alguien me puede dar un ejemplo de cómo hacerlo, sería genial.
Aquí está mi código actual:
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 {
//Called when the activity is first created.
@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);
}
Cualquier ayuda es apreciada.
fuente
El problema básico es que debe esperar la fase de dibujo para las mediciones reales (especialmente con valores dinámicos como
wrap_content
omatch_parent
), pero por lo general esta fase no se ha completadoonResume()
. Por lo tanto, necesita una solución alternativa para esperar esta fase. Hay diferentes soluciones posibles para esto:1. Escuche los eventos de Draw / Layout: ViewTreeObserver
Se dispara un ViewTreeObserver para diferentes eventos de dibujo. Por lo general, esto
OnGlobalLayoutListener
es lo que desea para obtener la medición, por lo que el código en el oyente se llamará después de la fase de diseño, para que las mediciones estén listas:Nota: El oyente se eliminará inmediatamente porque, de lo contrario, se activará en cada evento de diseño. Si tiene que admitir aplicaciones SDK Lvl <16, use esto para cancelar el registro del oyente:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Agregue un ejecutable a la cola de diseño: View.post ()
No muy conocido y mi solución favorita. Básicamente, solo use el método de publicación de View con su propio ejecutable. Básicamente, esto pone en cola su código después de la medida, el diseño, etc. de la vista según lo declarado por Romain Guy :
Ejemplo:
La ventaja sobre
ViewTreeObserver
:Referencias
3. Sobrescribir el método onLayout de Views
Esto solo es práctico en ciertas situaciones cuando la lógica se puede encapsular en la vista misma, de lo contrario, esta es una sintaxis bastante detallada y engorrosa.
También tenga en cuenta que onLayout se llamará muchas veces, así que tenga en cuenta lo que hace en el método o desactive su código después de la primera vez
4. Compruebe si ha pasado por la fase de diseño
Si tiene código que se ejecuta varias veces mientras crea la interfaz de usuario, puede usar el siguiente método de soporte v4 lib:
Adicional: obtener medidas estáticamente definidas
Si es suficiente obtener la altura / anchura estáticamente definidas, puede hacer esto con:
View.getMeasuredWidth()
View.getMeasuredHeigth()
Pero tenga en cuenta que esto podría ser diferente al ancho / alto real después del dibujo. El javadoc describe la diferencia perfectamente:
fuente
runOnUiThread(new Runnable() {...}
. Actualmente utilizo una variación de la primera método:addOnLayoutChangeListener
. No olvides eliminarlo luego dentro: removeOnLayoutChangeListener. Funciona desde el hilo de fondo también.android:visibility="gone"
, y en el otro proyecto, la propiedad de visibilidad erainvisible
. Si la visibilidad esgone
el ancho siempre será 0.Nosotros podemos usar
fuente
Usé esta solución, que creo que es mejor que onWindowFocusChanged (). Si abre un DialogFragment, luego gira el teléfono, se llamará a onWindowFocusChanged solo cuando el usuario cierre el diálogo):
Editar: como removeGlobalOnLayoutListener está en desuso, ahora debe hacer:
fuente
Como Ian afirma en este hilo de desarrolladores de Android :
fuente
Bottom line, if you call getWidth() etc. in a constructor, it will return zero.
Eso es un bingo. La raíz de mis problemas.Si necesita obtener el ancho de algún widget antes de que se muestre en la pantalla, puede usar getMeasuredWidth () o getMeasuredHeight ().
fuente
Prefiero usar en
OnPreDrawListener()
lugar deaddOnGlobalLayoutListener()
, ya que se llama un poco antes que otros oyentes.fuente
return false
los medios para cancelar el pase de dibujo actual . Para proceder, en sureturn true
lugar.Una extensión de Kotlin para observar en el diseño global y realizar una tarea determinada cuando la altura está lista dinámicamente.
Uso:
Implementación:
fuente
AndroidX tiene múltiples funciones de extensión que lo ayudan con este tipo de trabajo, dentro
androidx.core.view
Necesitas usar Kotlin para esto.
El que mejor se ajusta aquí es
doOnLayout
:En tu ejemplo:
Dependencia:
androidx.core:core-ktx:1.0.0
fuente
Un revestimiento si está utilizando RxJava y RxBindings . Enfoque similar sin el repetitivo. Esto también resuelve el truco para suprimir advertencias como en la respuesta de Tim Autin .
Eso es todo. No es necesario darse de baja, incluso si nunca se llama.
fuente
Ocurre porque la vista necesita más tiempo para inflarse. Entonces, en lugar de llamar
view.width
yview.height
en el hilo principal, debe usarview.post { ... }
para asegurarse de que suview
ya se ha inflado. En Kotlin:En Java, también puede llamar
getWidth()
ygetHeight()
métodos de unaRunnable
y pasar elRunnable
aview.post()
método.fuente
.post
no garantiza que la vista sea presentada.La altura y el ancho son cero porque la vista no se ha creado en el momento en que solicita su altura y ancho. Una solución más simple es
Este método es bueno en comparación con otros métodos, ya que es corto y crujiente.
fuente
Quizás esto ayude a alguien:
Crear una función de extensión para la clase Ver
Esto se puede usar en cualquier vista con:
fuente
La respuesta con
post
es incorrecta, ya que es posible que el tamaño no se vuelva a calcular.Otra cosa importante es que la vista y todos sus antepasados deben ser visibles . Para eso uso una propiedad
View.isShown
.Aquí está mi función kotlin, que se puede colocar en algún lugar en utils:
Y el uso es:
fuente
Si está usando Kotlin
fuente
Las vistas desaparecidas devuelven 0 como altura si la aplicación está en segundo plano. Este es mi código (1oo% funciona)
fuente
Necesitamos esperar a que se dibuje la vista. Para este propósito, use OnPreDrawListener. Ejemplo de Kotlin:
fuente