2012-02-23 13 views
8

Ho bisogno di sostituire frasi di testo in a con immagini e quindi aggiungerlo a un TextView. Per i Drawable regolari questo non è un problema, ma quando Drawable è un AnimationDrawable non so dove e quando chiamare .start();.Carica dinamicamente un'AnimationDrawable in una TextView

questo è come mi aggiungere testo al TextView:

textview.append(Html.fromHtml(textWithHtmlImgTags, imagegetter, null)); 

I tag immagine nel textWithHtmlImgTags vengono sostituiti usando imagegetter:

new ImageGetter() 
{ 
    @Override 
    public Drawable getDrawable(String source) { 

     if(source.endsWith("_ani")) 
     { 
      Log.i("cmv", "This is an animated drawable."); 

      AnimationDrawable dra = (AnimationDrawable)res.getDrawable(sRes.get(source)); 
      dra.setBounds(0, 0, dra.getIntrinsicWidth(), dra.getIntrinsicHeight()); 
      dra.start(); // This doesn't work.. 

      return dra; 
     } 

     Drawable dr = res.getDrawable(sRes.get(source)); 
     dr.setBounds(0, 0, dr.getIntrinsicWidth(), dr.getIntrinsicHeight()); 
     return dr; 
    } 

}; 

vengono aggiunti miei AnimationDrawables, ma non sono animati (sono bloccati sul fotogramma 1).

Nella documentazione si dice:

E 'importante notare che il metodo start() ha invitato l'AnimationDrawable non può essere chiamato durante il metodo onCreate() della vostra attività, perché l'AnimationDrawable non è ancora pienamente attaccato alla finestra. Se vuoi riprodurre immediatamente l'animazione, senza richiedere l'interazione, puoi chiamarla dal metodo onWindowFocusChanged() nella tua attività, che verrà chiamata quando Android mette a fuoco la tua finestra.

Poiché le immagini vengono aggiunte dinamicamente, non penso che abbia nulla a che fare con onCreate(). Quindi suppongo che chiamo il mio .start() quando il mio drawable is not yet fully attached to the window, ma dove/quando/come dovrei chiamare?

Grazie in anticipo!

+0

dopo aver impostato i drawbales chiama 'textView.bringToFront()' e quindi chiama '.start()' per animare .. – MKJParekh

risposta

6

sono uscito con la soluzione. Nella tua TextView personalizzata:

(1) Innanzitutto, devi decidere i tempi di inizio e fine dell'animazione.

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 

    handleAnimationDrawable(true); 
} 

@Override 
protected void onDetachedFromWindow() { 
    super.onDetachedFromWindow(); 

    handleAnimationDrawable(false); 
} 

private void handleAnimationDrawable(boolean isPlay) { 
    CharSequence text = getText(); 
    if (text instanceof Spanned) { 
     Spanned span = (Spanned) text; 
     ImageSpan[] spans = span.getSpans(0, span.length() - 1, 
       ImageSpan.class); 
     for (ImageSpan s : spans) { 
      Drawable d = s.getDrawable(); 
      if (d instanceof AnimationDrawable) { 
       AnimationDrawable animationDrawable = (AnimationDrawable) d; 
       if (isPlay) { 
        animationDrawable.setCallback(this); 
        animationDrawable.start(); 
       } else { 
        animationDrawable.stop(); 
        animationDrawable.setCallback(null); 
       } 
      } 
     } 
    } 
} 

(2) E quindi implementare il proprio Drawable.Callback per attivare il ridisegno.

@Override 
public void invalidateDrawable(Drawable dr) { 
    invalidate(); 
} 

@Override 
public void scheduleDrawable(Drawable who, Runnable what, long when) { 
    if (who != null && what != null) { 
     mHandler.postAtTime(what, when); 
    } 
} 

@Override 
public void unscheduleDrawable(Drawable who, Runnable what) { 
    if (who != null && what != null) { 
     mHandler.removeCallbacks(what); 
    } 
} 
+0

Ottimo! Questo è esattamente ciò di cui avevo bisogno! –

1

Immagino che la domanda importante sia: quando effettui la chiamata?

textview.append(Html.fromHtml(textWithHtmlImgTags... 

Se si chiama questo dopo onCreate allora è possibile chiamare l'animation.start(). Se viene chiamato nel metodo onCreate(), vorrei:

  • mantiene l'elenco dei drawable generati in ImageGetter;
  • inizio chiamata() su tutti i drawable in onAttachedToWindow o onStart (non so se lavorano nella funzione onStart)
+0

Effettuo la chiamata più volte, la prima chiamata è in onCreate. Dopodiché viene chiamato un numero di volte superiore (ogni volta che l'applicazione riceve una risposta da un server). Ho provato a tenere un elenco di tutti i AnimationDrawables e avviarli su AttachedToWindow, ma rimangono bloccati sul primo frame. –

1

Vista implementa già Drawable.Callback quindi è necessario solo il seguente TextView prevale per visualizzare gli oggetti AnimationDrawable in un ImageSpan:

// comparing against drawables found in the spans is probably safer 
@Override 
protected boolean verifyDrawable(Drawable who) { 
    return (super.verifyDrawable(who) || who instanceof AnimationDrawable); 
} 

// again comparing against drawables found in the spans is probably safer 
@Override 
public void invalidateDrawable(Drawable drawable) { 
    if (drawable instanceof AnimationDrawable) { 
     onLayout(true, getLeft(), getTop(), getRight(), getBottom()); 
     invalidate(); 
     return; 
    } 
    super.invalidateDrawable(drawable); 
} 

Overriding verifyDrawable è necessario in modo che le implementazioni classe Super di Drawable.La callback accetterà gli oggetti Drawable inattesi e gestirà la pianificazione.

La chiamata a onLayout forza il TextView a invalidare la sua lista di visualizzazione memorizzata nella cache, altrimenti i frame aggiornati non vengono disegnati.

Ho anche scoperto che, per qualche motivo, se ho creato ImageSpan riferendosi all'ID risorsa animazione, la risorsa non è stata memorizzata nella cache e sembrava essere ricaricata ogni volta che veniva chiamato ImageSpan.getDrawable(). Caricando la risorsa, impostandone i limiti e passandola al costruttore di ImageSpan ho evitato questo problema.

utilizzare onAttachedToWindow/onDetachedFromWindow come altrimenti suggerito.

Problemi correlati