2012-02-23 3 views
8

Мне нужно заменить фразы текста в изображениях, а затем добавить это в TextView. Для обычных Drawables это не проблема, но когда Drawable является AnimationDrawable, я не знаю, где и когда нужно позвонить .start();.Динамически загружать AnimationDrawable в TextView

Это, как я добавить текст в TextView:

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

Образ тегов в textWithHtmlImgTags замещаются с помощью 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; 
    } 

}; 

добавлены Мои AnimationDrawables, но они не анимированы (они застревают на кадре 1).

В документации говорится:

Важно отметить, что метод запуска() вызывалась на AnimationDrawable нельзя назвать при методе OnCreate() вашей деятельности, потому что AnimationDrawable еще не полностью прикрепленный к окну. Если вы хотите немедленно воспроизвести анимацию, не требуя взаимодействия, вы можете вызвать ее из метода onWindowFocusChanged() в своей Activity, который вызывается, когда Android переключит ваше окно в фокус.

Поскольку изображения добавляются динамически, я не думаю, что это имеет какое-либо отношение к onCreate(). Так что я догадываюсь, что я позвоню своему .start(), когда мой номер is not yet fully attached to the window, но где/когда/как должен Я называю это?

Заранее благодарен!

+0

после установки drawbales вызывать 'textView.bringToFront()', а затем вызывать '.start()' для анимации .. – MKJParekh

ответ

6

Я вышел с решением. В вашем обычном TextView:

(1) Сначала вам нужно определить время начала и остановки анимации.

@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) И затем реализовать свой собственный Drawable.Callback, чтобы вызвать перерисовку.

@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

Отлично! Это именно то, что мне нужно! –

1

Я думаю, что важный вопрос: когда вы звоните?

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

Если вы вызываете это после onCreate, вы можете вызвать анимацию.start(). Если он вызван методом onCreate(), я бы:

  • сохранить список чертежей, сгенерированных в ImageGetter;
  • начала вызова() на всех в onAttachedToWindow вводимого коэффициента или OnStart (не уверен, если они работают в функции OnStart)
+0

Я делаю вызов несколько раз, первый вызов находится в onCreate. После этого его вызывают в несколько раз больше (каждый раз, когда приложение получает ответ от сервера). Я попытался сохранить список всех AnimationDrawables и запустить их onAttachedToWindow, но все же они остаются застрявшими в первом кадре. –

1

Просмотр уже реализует Drawable.Callback поэтому вам необходимо следующее TextView переопределяет для отображения AnimationDrawable объектов в 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); 
} 

Перекрытие verifyDrawable необходимо так, чтобы супер класс реализации Drawable.Обратный вызов будет принимать неожиданные объекты Drawable и обрабатывать графики.

Вызов onLayout заставляет TextView аннулировать свой кешированный список отображения, иначе обновленные кадры не будут нарисованы.

Я также обнаружил, что по какой-то причине, если я создал ImageSpan, ссылаясь на идентификатор ресурса анимации, ресурс не был кэширован и, казалось, перезагружался каждый раз при вызове ImageSpan.getDrawable(). Загружая ресурс, устанавливая его границы и передавая его в конструктор ImageSpan, я избегал этой проблемы.

использовать onAttachedToWindow/onDetachedFromWindow в качестве альтернативы.

Смежные вопросы