Dynamicznie tworzę wszystkie elementy mojego projektu na Androida. Próbuję uzyskać szerokość i wysokość przycisku, aby móc go obrócić. Próbuję tylko nauczyć się, jak pracować z językiem Androida. Zwraca jednak 0.
Przeprowadziłem badania i zauważyłem, że należy to zrobić gdzieś indziej niż w onCreate()
metodzie. Gdyby ktoś mógł podać mi przykład, jak to zrobić, byłoby świetnie.
Oto mój obecny kod:
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);
}
Każda pomoc jest mile widziana.
źródło
Podstawowym problemem jest to, że trzeba czekać na fazę rysowania dla rzeczywistych pomiarów (szczególnie z wartościami dynamicznymi, takimi jak
wrap_content
lubmatch_parent
), ale zazwyczaj ta faza nie została jeszcze ukończonaonResume()
. Potrzebujesz obejścia, aby poczekać na tę fazę. Istnieją różne możliwe rozwiązania tego:1. Słuchaj zdarzeń losowania / układu: ViewTreeObserver
ViewTreeObserver zostaje zwolniony dla różnych zdarzeń rysowania. Zwykle
OnGlobalLayoutListener
jest to, co chcesz uzyskać pomiar, więc kod w detektorze zostanie wywołany po fazie układu, więc pomiary są gotowe:Uwaga: Detektor zostanie natychmiast usunięty, ponieważ w przeciwnym razie będzie uruchamiany przy każdym zdarzeniu układu. Jeśli musisz obsługiwać aplikacje SDK Lvl <16, użyj tego do wyrejestrowania nasłuchującego:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Dodaj plik wykonywalny do kolejki układu: View.post ()
Niezbyt dobrze znane i moje ulubione rozwiązanie. Zasadniczo po prostu użyj metody postu View z własnym runnable. To w zasadzie umieszcza kod w kolejce po takcie widoku, układzie itp., Jak stwierdził Romain Guy :
Przykład:
Przewaga nad
ViewTreeObserver
:Bibliografia:
3. Nadpisz metodę ViewLayout
Jest to praktyczne tylko w niektórych sytuacjach, gdy logikę można zamknąć w samym widoku, w przeciwnym razie jest to dość pełna i nieporęczna składnia.
Pamiętaj też, że onLayout będzie wywoływany wiele razy, więc zastanów się, co robisz w metodzie, lub wyłącz swój kod po raz pierwszy
4. Sprawdź, czy przeszedł fazę układu
Jeśli masz kod, który wykonuje się wiele razy podczas tworzenia interfejsu użytkownika, możesz użyć następującej metody wsparcia v4 lib:
Dodatkowo: uzyskiwanie statycznie zdefiniowanych pomiarów
Jeśli wystarczy uzyskać statycznie zdefiniowaną wysokość / szerokość, możesz to zrobić za pomocą:
View.getMeasuredWidth()
View.getMeasuredHeigth()
Pamiętaj jednak, że po rysowaniu może się ona różnić od rzeczywistej szerokości / wysokości. Jawadok doskonale opisuje różnicę:
źródło
runOnUiThread(new Runnable() {...}
. Obecnie używam odmianę metody 1:addOnLayoutChangeListener
. Nie zapomnij usunąć go następnie w środku: removeOnLayoutChangeListener. Działa również z wątku w tle.android:visibility="gone"
, aw drugim projekcie była właściwość widocznościinvisible
. Jeśli widoczność jest widoczna,gone
szerokość będzie zawsze wynosić 0.Możemy użyć
źródło
Użyłem tego rozwiązania, które moim zdaniem jest lepsze niż onWindowFocusChanged (). Jeśli otworzysz DialogFragment, a następnie obrócisz telefon, onWindowFocusChanged zostanie wywołany tylko wtedy, gdy użytkownik zamknie okno dialogowe):
Edycja: ponieważ removeGlobalOnLayoutListener jest przestarzałe, powinieneś teraz:
źródło
Jak stwierdza Ian w tym wątku dla programistów Androida :
źródło
Bottom line, if you call getWidth() etc. in a constructor, it will return zero.
to bingo. Źródło moich problemów.Jeśli chcesz uzyskać szerokość jakiegoś widżetu, zanim zostanie on wyświetlony na ekranie, możesz użyć getMeasuredWidth () lub getMeasuredHeight ().
źródło
Wolałbym używać
OnPreDrawListener()
zamiastaddOnGlobalLayoutListener()
, ponieważ nazywa się to nieco wcześniej niż inni słuchacze.źródło
return false
oznacza to anulowanie aktualnego przebiegu rysowania .return true
Zamiast tego kontynuować .Rozszerzenie Kotlin do obserwacji globalnego układu i wykonywania określonego zadania, gdy wysokość jest dynamicznie gotowa.
Stosowanie:
Realizacja:
źródło
AndroidX ma wiele funkcji rozszerzenia, które pomagają w tego rodzaju pracy wewnątrz
androidx.core.view
W tym celu musisz użyć Kotlina.
Ten, który najlepiej tu pasuje, to
doOnLayout
:W twoim przykładzie:
Zależność:
androidx.core:core-ktx:1.0.0
źródło
Jedna wkładka, jeśli używasz RxJava i RxBindings . Podobne podejście bez płyty kotłowej. To także rozwiązuje problem hakowania, aby ukryć ostrzeżenia, jak w odpowiedzi Tima Autina .
To jest to. Nie musisz rezygnować z subskrypcji, nawet jeśli nigdy nie dzwonisz.
źródło
Dzieje się tak, ponieważ widok potrzebuje więcej czasu na zawyżenie. Więc zamiast dzwonić
view.width
iview.height
w głównym wątku, powinieneś użyć,view.post { ... }
aby upewnić się, że twójview
został już napompowany. W Kotlinie:W Javie można również zadzwonić
getWidth()
igetHeight()
metod wRunnable
i przekazaćRunnable
doview.post()
metody.źródło
.post
nie gwarantuje widoku.Wysokość i szerokość wynoszą zero, ponieważ widok nie został utworzony do momentu, gdy zażądasz jego wysokości i szerokości. Jednym z najprostszych rozwiązań jest
Ta metoda jest dobra w porównaniu do innych metod, ponieważ jest krótka i rześka.
źródło
Może to pomaga komuś:
Utwórz funkcję rozszerzenia dla klasy View
Można go następnie użyć w dowolnym widoku z:
źródło
Odpowiedź z
post
jest nieprawidłowa, ponieważ rozmiar może nie zostać ponownie obliczony.Inną ważną rzeczą jest to, że widok i wszyscy jego przodkowie muszą być widoczni . Do tego używam nieruchomości
View.isShown
.Oto moja funkcja kotlin, którą można umieścić gdzieś w utils:
A użycie to:
źródło
Jeśli używasz Kotlin
źródło
Brak wyświetleń zwraca 0 jako wysokość, jeśli aplikacja działa w tle. Ten mój kod (1oo% działa)
źródło
Musimy poczekać, aż widok zostanie narysowany. W tym celu użyj OnPreDrawListener. Przykład Kotlina:
źródło