2012-02-23 28 views
8

Tôi cần phải thay thế các cụm từ văn bản bằng một hình ảnh và sau đó gắn thêm vào một TextView. Đối với Drawables thường xuyên này là không có vấn đề, nhưng khi Drawable là một AnimationDrawable tôi không biết ở đâu và khi nào để gọi .start();.Tự động tải một AnimationDrawable trong một TextView

Đây là cách tôi thêm văn bản vào TextView:

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

Các thẻ hình ảnh trong textWithHtmlImgTags được thay thế bằng 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 tôi được thêm vào, nhưng họ không được hoạt hình (chúng bị mắc kẹt trên khung 1).

Trong tài liệu hướng dẫn nó nói:

Điều quan trọng cần lưu ý là start() phương pháp kêu gọi AnimationDrawable không thể được gọi trong phương pháp onCreate() của hoạt động của bạn, bởi vì AnimationDrawable chưa đầy đủ gắn liền với cửa sổ. Nếu bạn muốn phát hoạt ảnh ngay lập tức, mà không cần tương tác, thì bạn có thể muốn gọi nó từ phương thức onWindowFocusChanged() trong Hoạt động của bạn, sẽ được gọi khi Android đưa cửa sổ của bạn vào tiêu điểm.

Vì hình ảnh được thêm động nên tôi không nghĩ rằng nó có liên quan gì đến onCreate(). Vì vậy, tôi đoán tôi gọi số .start() khi có thể draw is not yet fully attached to the window, nhưng ở đâu/khi nào/như thế nào nên Tôi gọi nó là?

Cảm ơn trước!

+0

sau khi thiết lập drawbales gọi 'textView.bringToFront()' và sau đó gọi '.start()' để animate .. – MKJParekh

Trả lời

6

tôi ra đến với các giải pháp. Trong TextView tùy chỉnh của bạn:

(1) Trước tiên, bạn phải quyết định thời gian bắt đầu và dừng hoạt ảnh.

@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) Và sau đó triển khai Drawable.Callback của riêng bạn để kích hoạt vẽ lại.

@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

Tuyệt vời! Đây chính xác là những gì tôi cần! –

1

Tôi đoán câu hỏi quan trọng là: khi nào bạn thực hiện cuộc gọi?

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

Nếu bạn đang gọi điều này sau onCreate thì bạn có thể gọi animation.start(). Nếu nó được gọi trong phương thức onCreate(), tôi sẽ:

  • giữ danh sách các đối tượng được tạo trong ImageGetter;
  • gọi start() trên tất cả các drawables trong onAttachedToWindow hoặc onStart (không chắc chắn nếu họ làm việc trong hàm onStart)
+0

Tôi thực hiện cuộc gọi nhiều lần, cuộc gọi đầu tiên là onCreate. Sau đó, nó được gọi nhiều lần (mỗi khi ứng dụng nhận được phản hồi từ máy chủ). Tôi đã thử giữ một danh sách tất cả các AnimationDrawables và bắt đầu chúng trênAttachedToWindow, nhưng chúng vẫn còn bị mắc kẹt trên frame đầu tiên. –

1

Xem đã thực hiện Drawable.Callback vì vậy bạn chỉ cần TextView sau sẽ ghi đè để hiển thị đối tượng AnimationDrawable trong một 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 là cần thiết để các lớp siêu hiện thực của drawable.Gọi lại sẽ chấp nhận các đối tượng Drawable bất ngờ và lập lịch biểu xử lý.

Gọi onLayout buộc TextView làm mất hiệu lực danh sách hiển thị được lưu trong bộ nhớ cache nếu không khung được cập nhật không được vẽ.

Tôi cũng thấy rằng vì lý do nào đó nếu tôi tạo ImageSpan đề cập đến id tài nguyên hoạt ảnh, tài nguyên không được lưu trữ và dường như được tải lại mỗi khi ImageSpan.getDrawable() được gọi. Bằng cách tải tài nguyên, thiết lập các giới hạn của nó và chuyển nó tới bộ tạo hình ImageSpan, tôi đã tránh được vấn đề đó.

sử dụng trênAttachedToWindow/onDetachedFromWindow như đề xuất khác.

Các vấn đề liên quan