Estou criando todos os elementos no meu projeto android dinamicamente. Estou tentando obter a largura e a altura de um botão para poder girá-lo. Estou apenas tentando aprender a trabalhar com o idioma do Android. No entanto, ele retorna 0.
Eu fiz algumas pesquisas e vi que isso precisa ser feito em outro lugar que não o onCreate()
método. Se alguém puder me dar um exemplo de como fazê-lo, isso seria ótimo.
Aqui está meu código atual:
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);
}
Qualquer ajuda é apreciada.
fonte
O problema básico é que você precisa aguardar a fase de desenho para as medições reais (especialmente com valores dinâmicos como
wrap_content
oumatch_parent
), mas geralmente essa fase ainda não foi concluídaonResume()
. Portanto, você precisa de uma solução alternativa para aguardar essa fase. Existem diferentes soluções possíveis para isso:1. Ouça eventos de desenho / layout: ViewTreeObserver
Um ViewTreeObserver é acionado para diferentes eventos de desenho. Normalmente,
OnGlobalLayoutListener
é isso que você deseja para obter a medição, para que o código no ouvinte seja chamado após a fase de layout, para que as medidas estejam prontas:Nota: O ouvinte será removido imediatamente, caso contrário, será acionado em todos os eventos de layout. Se você precisar oferecer suporte a aplicativos SDK Nvl <16, use-o para cancelar o registro do ouvinte:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Adicione um executável à fila de layout: View.post ()
Não é muito conhecido e minha solução favorita. Basicamente, basta usar o método de postagem do View com seu próprio executável. Isso basicamente enfileira seu código após a medida, o layout etc. da exibição, conforme declarado por Romain Guy :
Exemplo:
A vantagem sobre
ViewTreeObserver
:Referências:
3. Substituir o método onLayout do Views
Isso é prático apenas em determinadas situações em que a lógica pode ser encapsulada na própria exibição, caso contrário, essa é uma sintaxe bastante detalhada e complicada.
Lembre-se também de que onLayout será chamado várias vezes; portanto, considere o que você faz no método ou desative seu código após a primeira vez.
4. Verifique se passou pela fase de layout
Se você tiver um código executando várias vezes ao criar a interface do usuário, poderá usar o seguinte método de suporte v4 lib:
Adicional: Obtendo medidas definidas estática
Se basta obter a altura / largura definida estaticamente, você pode fazer isso com:
View.getMeasuredWidth()
View.getMeasuredHeigth()
Mas lembre-se de que isso pode ser diferente da largura / altura real após o desenho. O javadoc descreve a diferença perfeitamente:
fonte
runOnUiThread(new Runnable() {...}
. Atualmente eu uso uma variação do 1º método:addOnLayoutChangeListener
. Não se esqueça de removê-lo e dentro de: removeOnLayoutChangeListener. Também funciona a partir do thread de segundo plano.android:visibility="gone"
e, no outro, a propriedade de visibilidade erainvisible
. Se a visibilidade égone
a largura será sempre 0.Podemos usar
fonte
Usei essa solução, que acho melhor do que onWindowFocusChanged (). Se você abrir um DialogFragment e girar o telefone, onWindowFocusChanged será chamado somente quando o usuário fechar a caixa de diálogo):
Editar: como removeGlobalOnLayoutListener está obsoleto, você deve fazer agora:
fonte
Como Ian afirma neste segmento de desenvolvedores do Android :
fonte
Bottom line, if you call getWidth() etc. in a constructor, it will return zero.
isso é um bingo. A raiz dos meus problemas.Se você precisar obter a largura de algum widget antes que ele seja exibido na tela, use getMeasuredWidth () ou getMeasuredHeight ().
fonte
Eu preferiria usar em
OnPreDrawListener()
vez deaddOnGlobalLayoutListener()
, uma vez que é chamado um pouco mais cedo do que outros ouvintes.fonte
return false
meios para cancelar o passe desenho atual . Para prosseguir, emreturn true
vez disso.Uma extensão Kotlin para observar no layout global e executar uma determinada tarefa quando a altura estiver pronta dinamicamente.
Uso:
Implementação:
fonte
O AndroidX possui várias funções de extensão que ajudam você nesse tipo de trabalho, dentro
androidx.core.view
Você precisa usar o Kotlin para isso.
O que melhor se encaixa aqui é
doOnLayout
:No seu exemplo:
Dependência:
androidx.core:core-ktx:1.0.0
fonte
Um liner, se você estiver usando RxJava e RxBindings . Abordagem semelhante sem o clichê. Isso também resolve o hack para suprimir avisos, como na resposta de Tim Autin .
É isso. Não é necessário cancelar a assinatura, mesmo que nunca tenha sido chamado.
fonte
Isso acontece porque a visualização precisa de mais tempo para ser inflada. Portanto, em vez de chamar
view.width
eview.height
no segmento principal, você deveview.post { ... }
se certificar de que o seuview
já foi inflado. Em Kotlin:Em Java, você também pode chamar
getWidth()
egetHeight()
métodos em aRunnable
e passar o métodoRunnable
paraview.post()
.fonte
.post
não garante que a exibição seja apresentada.A altura e a largura são zero porque a visualização não foi criada quando você solicita a altura e a largura. Uma solução mais simples é
Este método é bom em comparação com outros métodos, pois é curto e nítido.
fonte
Talvez isso ajude alguém:
Crie uma função de extensão para a classe View
Isso pode ser usado em qualquer visualização com:
fonte
A resposta com
post
está incorreta, porque o tamanho pode não ser recalculado.Outra coisa importante é que a visão e todos os seus ancestrais devem estar visíveis . Para isso eu uso uma propriedade
View.isShown
.Aqui está minha função kotlin, que pode ser colocada em algum lugar nos utils:
E o uso é:
fonte
Se você estiver usando o Kotlin
fonte
As visualizações desaparecidas retornam 0 como altura se o aplicativo estiver em segundo plano. Este meu código (1oo% funciona)
fonte
Precisamos esperar que a visualização seja desenhada. Para esse fim, use OnPreDrawListener. Exemplo de Kotlin:
fonte