Ich erstelle alle Elemente in meinem Android-Projekt dynamisch. Ich versuche, die Breite und Höhe eines Knopfes zu ermitteln, damit ich diesen Knopf drehen kann. Ich versuche nur zu lernen, wie man mit der Android-Sprache arbeitet. Es wird jedoch 0 zurückgegeben.
Ich habe einige Nachforschungen angestellt und festgestellt, dass dies an einem anderen Ort als in der onCreate()
Methode erfolgen muss. Wenn mir jemand ein Beispiel geben kann, wie es geht, wäre das großartig.
Hier ist mein aktueller Code:
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);
}
Jede Hilfe wird geschätzt.
quelle
Das Grundproblem besteht darin, dass Sie auf die Zeichnungsphase für die tatsächlichen Messungen warten müssen (insbesondere bei dynamischen Werten wie
wrap_content
odermatch_parent
), diese Phase jedoch normalerweise noch nicht abgeschlossen istonResume()
. Sie benötigen also eine Problemumgehung, um auf diese Phase zu warten. Hierfür gibt es verschiedene mögliche Lösungen:1. Hören Sie sich Zeichen- / Layoutereignisse an: ViewTreeObserver
Ein ViewTreeObserver wird für verschiedene Zeichenereignisse ausgelöst. Normalerweise
OnGlobalLayoutListener
ist dies das, was Sie möchten, um die Messung zu erhalten, sodass der Code im Listener nach der Layoutphase aufgerufen wird, damit die Messungen fertig sind:Hinweis: Der Listener wird sofort entfernt, da er sonst bei jedem Layoutereignis ausgelöst wird. Wenn Sie Apps SDK Lvl <16 unterstützen müssen, verwenden Sie diese Option, um die Registrierung des Listeners aufzuheben :
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Fügen Sie der Layout-Warteschlange eine ausführbare Datei hinzu: View.post ()
Nicht sehr bekannt und meine Lieblingslösung. Verwenden Sie einfach die Post-Methode der Ansicht mit Ihrer eigenen ausführbaren Datei. Dies stellt Ihren Code im Grunde genommen nach dem Maß, dem Layout usw. der Ansicht in die Warteschlange , wie von Romain Guy angegeben :
Beispiel:
Der Vorteil gegenüber
ViewTreeObserver
:Verweise:
3. Überschreiben Sie die onLayout-Methode von Views
Dies ist nur in bestimmten Situationen praktisch, wenn die Logik in der Ansicht selbst gekapselt werden kann, andernfalls ist dies eine recht ausführliche und umständliche Syntax.
Beachten Sie auch, dass onLayout viele Male aufgerufen wird. Überlegen Sie also, was Sie in der Methode tun, oder deaktivieren Sie Ihren Code nach dem ersten Mal
4. Überprüfen Sie, ob die Layoutphase durchlaufen wurde
Wenn Sie Code haben, der beim Erstellen der Benutzeroberfläche mehrmals ausgeführt wird, können Sie die folgende Support-Methode v4 lib verwenden:
Zusätzlich: Statisch definierte Messungen erhalten
Wenn es ausreicht, nur die statisch definierte Höhe / Breite zu erhalten, können Sie dies einfach tun mit:
View.getMeasuredWidth()
View.getMeasuredHeigth()
Beachten Sie jedoch, dass dies nach dem Zeichnen möglicherweise von der tatsächlichen Breite / Höhe abweicht. Der Javadoc beschreibt den Unterschied perfekt:
quelle
runOnUiThread(new Runnable() {...}
. Derzeit verwende ich eine Variation der 1. Methode :addOnLayoutChangeListener
. Vergessen Sie nicht, es dann im Inneren zu entfernen: removeOnLayoutChangeListener. Es funktioniert auch vom Hintergrund-Thread.android:visibility="gone"
, und in dem anderen Projekt war die Sichtbarkeitseigenschaftinvisible
. Wenn die Sichtbarkeit ist, wirdgone
die Breite immer 0 sein.Wir können benutzen
quelle
Ich habe diese Lösung verwendet, die meiner Meinung nach besser ist als onWindowFocusChanged (). Wenn Sie ein DialogFragment öffnen und dann das Telefon drehen, wird onWindowFocusChanged nur aufgerufen, wenn der Benutzer den Dialog schließt.
Bearbeiten: Da removeGlobalOnLayoutListener veraltet ist, sollten Sie jetzt Folgendes tun:
quelle
Wie Ian in diesem Thread für Android-Entwickler feststellt :
quelle
Bottom line, if you call getWidth() etc. in a constructor, it will return zero.
Das ist ein Bingo. Die Wurzel meiner Probleme.Wenn Sie die Breite eines Widgets abrufen müssen, bevor es auf dem Bildschirm angezeigt wird, können Sie getMeasuredWidth () oder getMeasuredHeight () verwenden.
quelle
Ich würde lieber
OnPreDrawListener()
statt verwendenaddOnGlobalLayoutListener()
, da es etwas früher als andere Hörer aufgerufen wird.quelle
return false
bedeutet , den aktuellen Zeichnungsdurchlauf abzubrechen . Fahren Siereturn true
stattdessen fort.Eine Kotlin-Erweiterung, um das globale Layout zu beobachten und eine bestimmte Aufgabe auszuführen, wenn die Höhe dynamisch bereit ist.
Verwendungszweck:
Implementierung:
quelle
AndroidX verfügt über mehrere Erweiterungsfunktionen, die Sie bei dieser Art von Arbeit unterstützen
androidx.core.view
Sie müssen dafür Kotlin verwenden.
Das, was hier am besten passt, ist
doOnLayout
:In Ihrem Beispiel:
Abhängigkeit:
androidx.core:core-ktx:1.0.0
quelle
Ein Liner, wenn Sie RxJava & RxBindings verwenden . Ähnlicher Ansatz ohne Boilerplate. Dies löst auch den Hack, um Warnungen wie in der Antwort von Tim Autin zu unterdrücken .
Das ist es. Sie müssen sich nicht abmelden, auch wenn Sie nie angerufen haben.
quelle
Dies geschieht, weil die Ansicht mehr Zeit benötigt, um aufgeblasen zu werden. Anstatt aufzurufen
view.width
undview.height
den Haupt-Thread zu aktivieren, sollten Sieview.post { ... }
sicherstellen, dass Ihr Threadview
bereits aufgeblasen ist. In Kotlin:In Java können Sie auch
getWidth()
undgetHeight()
Methoden in a aufrufen undRunnable
dieRunnable
to-view.post()
Methode übergeben.quelle
.post
garantiert aber nicht, dass die Ansicht angelegt wird.Höhe und Breite sind Null, da die Ansicht zum Zeitpunkt der Anforderung von Höhe und Breite noch nicht erstellt wurde. Eine einfachste Lösung ist
Diese Methode ist im Vergleich zu anderen Methoden gut, da sie kurz und knackig ist.
quelle
Vielleicht hilft das jemandem:
Erstellen Sie eine Erweiterungsfunktion für die View-Klasse
Dies kann dann in jeder Ansicht verwendet werden mit:
quelle
Die Antwort mit
post
ist falsch, da die Größe möglicherweise nicht neu berechnet wird.Eine weitere wichtige Sache ist, dass die Ansicht und alle Vorfahren sichtbar sein müssen . Dafür benutze ich eine Eigenschaft
View.isShown
.Hier ist meine Kotlin-Funktion, die irgendwo in Utils platziert werden kann:
Und die Verwendung ist:
quelle
Wenn Sie Kotlin verwenden
quelle
Gone Views gibt 0 als Höhe zurück, wenn die App im Hintergrund angezeigt wird. Dies ist mein Code (1oo% funktioniert)
quelle
Wir müssen warten, bis die Ansicht gezeichnet wird. Verwenden Sie dazu den OnPreDrawListener. Kotlin Beispiel:
quelle