2011-10-11 19 views
151

Mam niestandardowy widok, który rysuje przewijaną mapę bitową na ekranie. Aby go zainicjować, muszę przekazać rozmiar w pikselach obiektu nadrzędnego. Ale podczas funkcji onCreate i onResume Układ nie został jeszcze narysowany, a więc layout.getMeasuredHeight() zwraca 0.Jak określić, kiedy układ został narysowany?

Jako obejście dodałem program obsługi, aby odczekać jedną sekundę, a następnie zmierzyć. To działa, ale jest niechlujne i nie mam pojęcia, jak bardzo mogę przyciąć czas, zanim skończę, zanim układ zostanie narysowany.

Co chcę wiedzieć, jak wykryć, kiedy układ zostanie narysowany? Czy istnieje zdarzenie lub oddzwanianie?

Odpowiedz

316

Możesz dodać obserwatora drzewa do układu. Powinno to zwrócić prawidłową szerokość i wysokość. onCreate() jest wywoływane przed wykonaniem układu widoków podrzędnych. Więc szerokość i wysokość nie są jeszcze obliczane. Aby uzyskać wysokość i szerokość, umieścić to na metodzie onCreate():

final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID); 
ViewTreeObserver vto = layout.getViewTreeObserver(); 
vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() { 
    @Override 
    public void onGlobalLayout() { 
     layout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
     int width = layout.getMeasuredWidth(); 
     int height = layout.getMeasuredHeight(); 

    } 
}); 
+1

To działało. Dzięki! ViewTreeObserver jest dokładnie tym, czego chciałem. –

+0

Wielkie dzięki! Dokładnie przykład, którego szukałem, w tym natychmiastowe usunięcie słuchacza przy pierwszym uruchomieniu. – baske

+0

Tak, tak powiedział Romain Guy! –

1

Kiedy onMeasure nazywa widok dostaje swoją zmierzoną szerokość/wysokość. Następnie możesz zadzwonić pod numer layout.getMeasuredHeight().

+3

Czy nie trzeba tworzyć własnego widoku, aby wiedzieć, kiedy uruchamiane jest narzędzie onMeasure? –

+0

Tak, musisz użyć widoków niestandardowych, aby uzyskać dostęp na miarę. –

2

Kolejna odpowiedź to:
Spróbuj sprawdzić wymiary widoku pod numerem onWindowFocusChanged.

18

Aby uniknąć kod przestarzały i ostrzeżenia można użyć:

view.getViewTreeObserver().addOnGlobalLayoutListener(
     new ViewTreeObserver.OnGlobalLayoutListener() { 
      @SuppressWarnings("deprecation") 
      @Override 
      public void onGlobalLayout() { 
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
        view.getViewTreeObserver() 
          .removeOnGlobalLayoutListener(this); 
       } else { 
        view.getViewTreeObserver() 
          .removeGlobalOnLayoutListener(this); 
       } 
       yourFunctionHere(); 
      } 
     }); 
+1

Aby korzystać z tego kodu, "widok" musi być zadeklarowany jako "ostateczny". – BeccaP

+2

użyj tego warunku zamiast Build.VERSION.SDK_INT HendraWD

35

bardzo prosty sposób jest po prostu zadzwonić post() od układu. Spowoduje to uruchomienie kodu w następnym kroku, po utworzeniu widoku.

YOUR_LAYOUT.post(new Runnable() { 
    @Override 
    public void run() { 
     int width = YOUR_LAYOUT.getMeasuredWidth(); 
     int height = YOUR_LAYOUT.getMeasuredHeight(); 
    } 
}); 
+2

Nie wiem, czy post faktycznie uruchomi kod po utworzeniu widoku. Nie ma żadnej gwarancji, ponieważ post po prostu doda Runnable, które utworzysz do RunQueue, do wykonania po poprzedniej kolejce wykonanej na wątku UI. – HendraWD

+4

Wręcz przeciwnie, post() jest wykonywany po następnej aktualizacji kroku interfejsu użytkownika, która ma miejsce po utworzeniu widoku. Dlatego masz gwarancję, że zostanie wykonany po utworzeniu widoku. – Elliptica

+0

Testowałem ten kod kilka razy, działa najlepiej tylko w wątku UI. W wątku tła czasami nie działa. – CoolMind

Powiązane problemy