2011-12-26 36 views
8

làm câu hỏi, tôi sử dụng ImageSpan để thêm hình ảnh vào TextView. nhưng nó không thể animate.Do bạn có bất kỳ tư vấn?
Tôi cố gắng mở rộng AnimationDrawable để thêm drawable vào ImageSpan. nhưng nó không hoạt độngCách thêm biểu tượng cảm xúc động trong TextView hoặc EditText trong Android

public class EmoticonDrawalbe extends AnimationDrawable { 
    private Bitmap bitmap; 
    private GifDecode decode; 
    private int gifCount; 

    public EmoticonDrawalbe(Context context, String source) { 
     decode = new GifDecode(); 
     decode.read(context, source); 
     gifCount = decode.getFrameCount(); 
     if (gifCount <= 0) { 
      return; 
     } 
     for (int i = 0; i < gifCount; i++) { 
      bitmap = decode.getFrame(i); 
      addFrame(new BitmapDrawable(bitmap), decode.getDelay(i)); 
     } 
     setOneShot(false); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     super.draw(canvas); 
     start(); 
    } 
} 

Trả lời

2

Bạn có thể sử dụng ObjectAnimator để animate drawable trong ImageSpan

http://developer.android.com/reference/android/animation/ObjectAnimator.html

+0

Thật tuyệt, tôi đã không nhận thấy lớp học này trước đây. Có vẻ thú vị, mặc dù nó chỉ hỗ trợ bắt đầu cấp API 11. –

+0

tks cho lời khuyên của bạn, tôi sẽ có một thử. – Stay

+0

Bạn có thể cung cấp một ví dụ không? Cảm ơn! – shiami

22

tôi sẽ cố gắng để một trong hai:

  • Chia hình ảnh hoạt hình (có lẽ là một tệp .gif?) vào các khung riêng biệt và kết hợp chúng thành một AnimationDrawable mà sau đó bạn chuyển đến hàm tạo của ImageSpan.
  • Phân lớp ImageSpan và ghi đè phương pháp onDraw() để thêm logic của riêng bạn để vẽ các khung khác nhau dựa trên một số loại bộ hẹn giờ. Có một bản demo api minh họa cách sử dụng lớp Movie để tải lên một gif động có thể đáng xem xét.

Big Edit: Được rồi, xin lỗi vì đã không nhận được trở lại trước đó, nhưng tôi đã phải dành một chút thời gian để điều tra này bản thân mình. Tôi đã có một trò chơi với nó vì tôi có lẽ sẽ cần một giải pháp cho bản thân mình cho một trong những dự án tương lai của tôi. Thật không may, tôi chạy vào các vấn đề tương tự với việc sử dụng một AnimationDrawable, mà dường như được gây ra bởi cơ chế bộ nhớ đệm mà DynamicDrawableSpan (một siêu lớp gián tiếp của ImageSpan) sử dụng.

Một vấn đề khác đối với tôi là có vẻ như không phải là một luồng đơn giản để vô hiệu hóa Bản vẽ hoặc ImageSpan. Có thể vẽ thực tế có các phương pháp invalidateDrawable(Drawable)invalidateSelf(), nhưng phương pháp đầu tiên không có bất kỳ ảnh hưởng nào trong trường hợp của tôi, trong khi phương thức thứ hai chỉ hoạt động nếu một số phép thuật Drawable.Callback được đính kèm. Tôi không thể tìm thấy bất kỳ tài liệu phong nha về cách sử dụng ...

Vì vậy, tôi đã đi một bước xa hơn lên cây logic để giải quyết vấn đề. Tôi phải thêm một cảnh báo trước rằng điều này rất có thể không phải là một giải pháp tối ưu, nhưng bây giờ đó là giải pháp duy nhất tôi có thể làm việc. Bạn có thể sẽ không gặp vấn đề gì nếu bạn sử dụng giải pháp của tôi một cách không thường xuyên, nhưng tôi sẽ tránh làm đầy toàn bộ màn hình bằng các biểu tượng cảm xúc bằng mọi cách. Tôi không chắc điều gì sẽ xảy ra, nhưng sau đó một lần nữa, tôi có lẽ thậm chí không muốn biết.

Nếu không có thêm quảng cáo, đây là mã. Tôi đã thêm một số nhận xét để làm cho nó tự giải thích. Nó khá có khả năng được sử dụng một lớp giải mã Gif khác nhau/libary, nhưng nó sẽ làm việc với về bất kỳ ra khỏi đó.

AnimatedGifDrawable.java

public class AnimatedGifDrawable extends AnimationDrawable { 

    private int mCurrentIndex = 0; 
    private UpdateListener mListener; 

    public AnimatedGifDrawable(InputStream source, UpdateListener listener) { 
     mListener = listener; 
     GifDecoder decoder = new GifDecoder(); 
     decoder.read(source); 

     // Iterate through the gif frames, add each as animation frame 
     for (int i = 0; i < decoder.getFrameCount(); i++) { 
      Bitmap bitmap = decoder.getFrame(i); 
      BitmapDrawable drawable = new BitmapDrawable(bitmap); 
      // Explicitly set the bounds in order for the frames to display 
      drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
      addFrame(drawable, decoder.getDelay(i)); 
      if (i == 0) { 
       // Also set the bounds for this container drawable 
       setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
      } 
     } 
    } 

    /** 
    * Naive method to proceed to next frame. Also notifies listener. 
    */ 
    public void nextFrame() { 
     mCurrentIndex = (mCurrentIndex + 1) % getNumberOfFrames(); 
     if (mListener != null) mListener.update(); 
    } 

    /** 
    * Return display duration for current frame 
    */ 
    public int getFrameDuration() { 
     return getDuration(mCurrentIndex); 
    } 

    /** 
    * Return drawable for current frame 
    */ 
    public Drawable getDrawable() { 
     return getFrame(mCurrentIndex); 
    } 

    /** 
    * Interface to notify listener to update/redraw 
    * Can't figure out how to invalidate the drawable (or span in which it sits) itself to force redraw 
    */ 
    public interface UpdateListener { 
     void update(); 
    } 

} 

AnimatedImageSpan.java

public class AnimatedImageSpan extends DynamicDrawableSpan { 

    private Drawable mDrawable; 

    public AnimatedImageSpan(Drawable d) { 
     super(); 
     mDrawable = d; 
     // Use handler for 'ticks' to proceed to next frame 
     final Handler mHandler = new Handler(); 
     mHandler.post(new Runnable() { 
      public void run() { 
       ((AnimatedGifDrawable)mDrawable).nextFrame(); 
       // Set next with a delay depending on the duration for this frame 
       mHandler.postDelayed(this, ((AnimatedGifDrawable)mDrawable).getFrameDuration()); 
      } 
     }); 
    } 

    /* 
    * Return current frame from animated drawable. Also acts as replacement for super.getCachedDrawable(), 
    * since we can't cache the 'image' of an animated image. 
    */ 
    @Override 
    public Drawable getDrawable() { 
     return ((AnimatedGifDrawable)mDrawable).getDrawable(); 
    } 

    /* 
    * Copy-paste of super.getSize(...) but use getDrawable() to get the image/frame to calculate the size, 
    * in stead of the cached drawable. 
    */ 
    @Override 
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { 
     Drawable d = getDrawable(); 
     Rect rect = d.getBounds(); 

     if (fm != null) { 
      fm.ascent = -rect.bottom; 
      fm.descent = 0; 

      fm.top = fm.ascent; 
      fm.bottom = 0; 
     } 

     return rect.right; 
    } 

    /* 
    * Copy-paste of super.draw(...) but use getDrawable() to get the image/frame to draw, in stead of 
    * the cached drawable. 
    */ 
    @Override 
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { 
     Drawable b = getDrawable(); 
     canvas.save(); 

     int transY = bottom - b.getBounds().bottom; 
     if (mVerticalAlignment == ALIGN_BASELINE) { 
      transY -= paint.getFontMetricsInt().descent; 
     } 

     canvas.translate(x, transY); 
     b.draw(canvas); 
     canvas.restore(); 

    } 

} 

Cách sử dụng:

final TextView gifTextView = (TextView) findViewById(R.id.gif_textview); 
SpannableStringBuilder sb = new SpannableStringBuilder(); 
sb.append("Text followed by animated gif: "); 
String dummyText = "dummy"; 
sb.append(dummyText); 
sb.setSpan(new AnimatedImageSpan(new AnimatedGifDrawable(getAssets().open("agif.gif"), new AnimatedGifDrawable.UpdateListener() { 
    @Override 
    public void update() { 
     gifTextView.postInvalidate(); 
    } 
})), sb.length() - dummyText.length(), sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
gifTextView.setText(sb); 

Như bạn có thể thấy tôi đã sử dụng một Trình xử lý để cung cấp các 've' để tiến tới khung tiếp theo.Ưu điểm của việc này là nó sẽ chỉ kích hoạt cập nhật bất cứ khi nào một khung mới sẽ được hiển thị. Việc vẽ lại thực tế được thực hiện bằng cách vô hiệu hóa TextView chứa AnimatedImageSpan. Đồng thời nhược điểm là bất cứ khi nào bạn có một loạt các gifs động trong cùng một TextView (hoặc nhiều cho rằng vấn đề), các quan điểm có thể được cập nhật như điên ... Sử dụng nó một cách khôn ngoan. :)

+0

tks cho lời khuyên của bạn, tôi sẽ có một thử. – Stay

+0

eh, StateDrawable là gì? – Stay

+0

Tôi xin lỗi, tôi phải có một cuộc khủng hoảng não tạm thời. Tôi muốn viết "[' AnimationDrawable'] (http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html) ". Tôi cũng sửa nó trong câu trả lời của mình. –

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