GifView 是一个为了解决android中现在没有直接显示gif的view,只能通过mediaplay来显示这个问题的项目,其用法和 ImageView一样,支持gif图片。可监视GIF是否加载成功。
GifView的功能: 播放Gif图片 Gif动画监听
Android GifView 的用法:
GifAction.java 观察者类,监视GIF是否加载成功
GifFrame.java 里面三个成员:当前图片、延时、下张Frame的链接。GifDecoder.java 解码线程类GifView.java 主类,包括常用方法,如GifView构造方法、设置图片源、延迟、绘制等。3 public interface GifAction { 4 /** 5 * gif解码观察者 6 * @param parseStatus 解码是否成功,成功会为true 7 * @param frameIndex 当前解码的第几帧,当全部解码成功后,这里为-1 8 */ 9 public void parseOk(boolean parseStatus,int frameIndex);10 }
1 import android.graphics.Bitmap; 2 3 public class GifFrame { 4 /** 5 * 构造函数 6 * @param im 图片 7 * @param del 延时 8 */ 9 public GifFrame(Bitmap im, int del) {10 image = im;11 delay = del;12 }13 /**图片*/14 public Bitmap image;15 /**延时*/16 public int delay;17 /**下一帧*/18 public GifFrame nextFrame = null;19 }
1 import java.io.ByteArrayInputStream; 2 import java.io.InputStream; 3 import android.graphics.Bitmap; 4 import android.graphics.Bitmap.Config; 5 6 public class GifDecoder extends Thread { 7 8 /** 状态:正在解码中 */ 9 public static final int STATUS_PARSING = 0; 10 /** 状态:图片格式错误 */ 11 public static final int STATUS_FORMAT_ERROR = 1; 12 /** 状态:打开失败 */ 13 public static final int STATUS_OPEN_ERROR = 2; 14 /** 状态:解码成功 */ 15 public static final int STATUS_FINISH = -1; 16 17 private InputStream in; 18 private int status; 19 20 public int width; // full image width 21 public int height; // full image height 22 private boolean gctFlag; // global color table used 23 private int gctSize; // size of global color table 24 private int loopCount = 1; // iterations; 0 = repeat forever 25 26 private int[] gct; // global color table 27 private int[] lct; // local color table 28 private int[] act; // active color table 29 30 private int bgIndex; // background color index 31 private int bgColor; // background color 32 private int lastBgColor; // previous bg color 33 private int pixelAspect; // pixel aspect ratio 34 35 private boolean lctFlag; // local color table flag 36 private boolean interlace; // interlace flag 37 private int lctSize; // local color table size 38 39 private int ix, iy, iw, ih; // current image rectangle 40 private int lrx, lry, lrw, lrh; 41 private Bitmap image; // current frame 42 private Bitmap lastImage; // previous frame 43 private GifFrame currentFrame = null; 44 45 private boolean isShow = false; 46 47 // current data block 48 private byte[] block = new byte[256]; 49 private int blockSize = 0; // block size 50 51 // last graphic control extension info 52 private int dispose = 0; 53 // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev 54 private int lastDispose = 0; 55 // use transparent color 56 private boolean transparency = false; 57 // delay in milliseconds 58 private int delay = 0; 59 // transparent color index 60 private int transIndex; 61 62 private static final int MaxStackSize = 4096; 63 // max decoder pixel stack size 64 65 // LZW decoder working arrays 66 private short[] prefix; 67 private byte[] suffix; 68 private byte[] pixelStack; 69 private byte[] pixels; 70 // frames read from current file 71 private GifFrame gifFrame; 72 private int frameCount; 73 74 private GifAction action = null; 75 76 private byte[] gifData = null; 77 78 public GifDecoder(byte[] data, GifAction act) { 79 gifData = data; 80 action = act; 81 } 82 83 public GifDecoder(InputStream is, GifAction act) { 84 in = is; 85 action = act; 86 } 87 88 public void run() { 89 if (in != null) { 90 readStream(); 91 } else if (gifData != null) { 92 readByte(); 93 } 94 } 95 96 /** 97 * 释放资源 98 */ 99 public void free() {100 GifFrame fg = gifFrame;101 while (fg != null) {102 fg.image = null;103 fg = null;104 gifFrame = gifFrame.nextFrame;105 fg = gifFrame;106 }107 if (in != null) {108 try {109 in.close();110 } catch (Exception ex) {111 }112 in = null;113 }114 gifData = null;115 }116 117 /**118 * 当前状态119 * @return120 */121 public int getStatus() {122 return status;123 }124 125 /**126 * 解码是否成功,成功返回true127 * @return 成功返回true,否则返回false128 */129 public boolean parseOk() {130 return status == STATUS_FINISH;131 }132 133 /**134 * 取某帧的延时时间135 * @param n136 * 第几帧137 * @return 延时时间,毫秒138 */139 public int getDelay(int n) {140 delay = -1;141 if ((n >= 0) && (n < frameCount)) {142 // delay = ((GifFrame) frames.elementAt(n)).delay;143 GifFrame f = getFrame(n);144 if (f != null)145 delay = f.delay;146 }147 return delay;148 }149 150 /**151 * 取所有帧的延时时间152 * @return153 */154 public int[] getDelays() {155 GifFrame f = gifFrame;156 int[] d = new int[frameCount];157 int i = 0;158 while (f != null && i < frameCount) {159 d[i] = f.delay;160 f = f.nextFrame;161 i++;162 }163 return d;164 }165 166 /**167 * 取总帧 数168 * @return 图片的总帧数169 */170 public int getFrameCount() {171 return frameCount;172 }173 174 /**175 * 取第一帧图片176 * @return177 */178 public Bitmap getImage() {179 return getFrameImage(0);180 }181 182 public int getLoopCount() {183 return loopCount;184 }185 186 private void setPixels() {187 int[] dest = new int[width * height];188 // fill in starting image contents based on last image's dispose code189 if (lastDispose > 0) {190 if (lastDispose == 3) {191 // use image before last192 int n = frameCount - 2;193 if (n > 0) {194 lastImage = getFrameImage(n - 1);195 } else {196 lastImage = null;197 }198 }199 if (lastImage != null) {200 lastImage.getPixels(dest, 0, width, 0, 0, width, height);201 // copy pixels202 if (lastDispose == 2) {203 // fill last image rect area with background color204 int c = 0;205 if (!transparency) {206 c = lastBgColor;207 }208 for (int i = 0; i < lrh; i++) {209 int n1 = (lry + i) * width + lrx;210 int n2 = n1 + lrw;211 for (int k = n1; k < n2; k++) {212 dest[k] = c;213 }214 }215 }216 }217 }218 219 // copy each source line to the appropriate place in the destination220 int pass = 1;221 int inc = 8;222 int iline = 0;223 for (int i = 0; i < ih; i++) {224 int line = i;225 if (interlace) {226 if (iline >= ih) {227 pass++;228 switch (pass) {229 case 2:230 iline = 4;231 break;232 case 3:233 iline = 2;234 inc = 4;235 break;236 case 4:237 iline = 1;238 inc = 2;239 }240 }241 line = iline;242 iline += inc;243 }244 line += iy;245 if (line < height) {246 int k = line * width;247 int dx = k + ix; // start of line in dest248 int dlim = dx + iw; // end of dest line249 if ((k + width) < dlim) {250 dlim = k + width; // past dest edge251 }252 int sx = i * iw; // start of line in source253 while (dx < dlim) {254 // map color and insert in destination255 int index = ((int) pixels[sx++]) & 0xff;256 int c = act[index];257 if (c != 0) {258 dest[dx] = c;259 }260 dx++;261 }262 }263 }264 image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444);265 }266 267 /**268 * 取第几帧的图片269 * 270 * @param n271 * 帧数272 * @return 可画的图片,如果没有此帧或者出错,返回null273 */274 public Bitmap getFrameImage(int n) {275 GifFrame frame = getFrame(n);276 if (frame == null)277 return null;278 else279 return frame.image;280 }281 282 /**283 * 取当前帧图片284 * 285 * @return 当前帧可画的图片286 */287 public GifFrame getCurrentFrame() {288 return currentFrame;289 }290 291 /**292 * 取第几帧,每帧包含了可画的图片和延时时间293 * 294 * @param n295 * 帧数296 * @return297 */298 public GifFrame getFrame(int n) {299 GifFrame frame = gifFrame;300 int i = 0;301 while (frame != null) {302 if (i == n) {303 return frame;304 } else {305 frame = frame.nextFrame;306 }307 i++;308 }309 return null;310 }311 312 /**313 * 重置,进行本操作后,会直接到第一帧314 */315 public void reset() {316 currentFrame = gifFrame;317 }318 319 /**320 * 下一帧,进行本操作后,通过getCurrentFrame得到的是下一帧321 * 322 * @return 返回下一帧323 */324 public GifFrame next() {325 if (isShow == false) {326 isShow = true;327 return gifFrame;328 } else {329 if (status == STATUS_PARSING) {330 if (currentFrame.nextFrame != null)331 currentFrame = currentFrame.nextFrame;332 // currentFrame = gifFrame;333 } else {334 currentFrame = currentFrame.nextFrame;335 if (currentFrame == null) {336 currentFrame = gifFrame;337 }338 }339 return currentFrame;340 }341 }342 343 private int readByte() {344 in = new ByteArrayInputStream(gifData);345 gifData = null;346 return readStream();347 }348 349 // public int read(byte[] data){350 // InputStream is = new ByteArrayInputStream(data);351 // return read(is);352 // }353 354 private int readStream() {355 init();356 if (in != null) {357 readHeader();358 if (!err()) {359 readContents();360 if (frameCount < 0) {361 status = STATUS_FORMAT_ERROR;362 action.parseOk(false, -1);363 } else {364 status = STATUS_FINISH;365 action.parseOk(true, -1);366 }367 }368 try {369 in.close();370 } catch (Exception e) {371 e.printStackTrace();372 }373 374 } else {375 status = STATUS_OPEN_ERROR;376 action.parseOk(false, -1);377 }378 return status;379 }380 381 private void decodeImageData() {382 int NullCode = -1;383 int npix = iw * ih;384 int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;385 386 if ((pixels == null) || (pixels.length < npix)) {387 pixels = new byte[npix]; // allocate new pixel array388 }389 if (prefix == null) {390 prefix = new short[MaxStackSize];391 }392 if (suffix == null) {393 suffix = new byte[MaxStackSize];394 }395 if (pixelStack == null) {396 pixelStack = new byte[MaxStackSize + 1];397 }398 // Initialize GIF data stream decoder.399 data_size = read();400 clear = 1 << data_size;401 end_of_information = clear + 1;402 available = clear + 2;403 old_code = NullCode;404 code_size = data_size + 1;405 code_mask = (1 << code_size) - 1;406 for (code = 0; code < clear; code++) {407 prefix[code] = 0;408 suffix[code] = (byte) code;409 }410 411 // Decode GIF pixel stream.412 datum = bits = count = first = top = pi = bi = 0;413 for (i = 0; i < npix;) {414 if (top == 0) {415 if (bits < code_size) {416 // Load bytes until there are enough bits for a code.417 if (count == 0) {418 // Read a new data block.419 count = readBlock();420 if (count <= 0) {421 break;422 }423 bi = 0;424 }425 datum += (((int) block[bi]) & 0xff) << bits;426 bits += 8;427 bi++;428 count--;429 continue;430 }431 // Get the next code.432 code = datum & code_mask;433 datum >>= code_size;434 bits -= code_size;435 436 // Interpret the code437 if ((code > available) || (code == end_of_information)) {438 break;439 }440 if (code == clear) {441 // Reset decoder.442 code_size = data_size + 1;443 code_mask = (1 << code_size) - 1;444 available = clear + 2;445 old_code = NullCode;446 continue;447 }448 if (old_code == NullCode) {449 pixelStack[top++] = suffix[code];450 old_code = code;451 first = code;452 continue;453 }454 in_code = code;455 if (code == available) {456 pixelStack[top++] = (byte) first;457 code = old_code;458 }459 while (code > clear) {460 pixelStack[top++] = suffix[code];461 code = prefix[code];462 }463 first = ((int) suffix[code]) & 0xff;464 // Add a new string to the string table,465 if (available >= MaxStackSize) {466 break;467 }468 pixelStack[top++] = (byte) first;469 prefix[available] = (short) old_code;470 suffix[available] = (byte) first;471 available++;472 if (((available & code_mask) == 0)473 && (available < MaxStackSize)) {474 code_size++;475 code_mask += available;476 }477 old_code = in_code;478 }479 480 // Pop a pixel off the pixel stack.481 top--;482 pixels[pi++] = pixelStack[top];483 i++;484 }485 for (i = pi; i < npix; i++) {486 pixels[i] = 0; // clear missing pixels487 }488 }489 490 private boolean err() {491 return status != STATUS_PARSING;492 }493 494 private void init() {495 status = STATUS_PARSING;496 frameCount = 0;497 gifFrame = null;498 gct = null;499 lct = null;500 }501 502 private int read() {503 int curByte = 0;504 try {505 506 curByte = in.read();507 } catch (Exception e) {508 status = STATUS_FORMAT_ERROR;509 }510 return curByte;511 }512 513 private int readBlock() {514 blockSize = read();515 int n = 0;516 if (blockSize > 0) {517 try {518 int count = 0;519 while (n < blockSize) {520 count = in.read(block, n, blockSize - n);521 if (count == -1) {522 break;523 }524 n += count;525 }526 } catch (Exception e) {527 e.printStackTrace();528 }529 if (n < blockSize) {530 status = STATUS_FORMAT_ERROR;531 }532 }533 return n;534 }535 536 private int[] readColorTable(int ncolors) {537 int nbytes = 3 * ncolors;538 int[] tab = null;539 byte[] c = new byte[nbytes];540 int n = 0;541 try {542 n = in.read(c);543 } catch (Exception e) {544 e.printStackTrace();545 }546 if (n < nbytes) {547 status = STATUS_FORMAT_ERROR;548 } else {549 tab = new int[256]; // max size to avoid bounds checks550 int i = 0;551 int j = 0;552 while (i < ncolors) {553 int r = ((int) c[j++]) & 0xff;554 int g = ((int) c[j++]) & 0xff;555 int b = ((int) c[j++]) & 0xff;556 tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;557 }558 }559 return tab;560 }561 562 private void readContents() {563 // read GIF file content blocks564 boolean done = false;565 while (!(done || err())) {566 int code = read();567 switch (code) {568 case 0x2C: // image separator569 readImage();570 break;571 case 0x21: // extension572 code = read();573 switch (code) {574 case 0xf9: // graphics control extension575 readGraphicControlExt();576 break;577 case 0xff: // application extension578 readBlock();579 String app = "";580 for (int i = 0; i < 11; i++) {581 app += (char) block[i];582 }583 if (app.equals("NETSCAPE2.0")) {584 readNetscapeExt();585 } else {586 skip(); // don't care587 }588 break;589 default: // uninteresting extension590 skip();591 }592 break;593 case 0x3b: // terminator594 done = true;595 break;596 case 0x00: // bad byte, but keep going and see what happens597 break;598 default:599 status = STATUS_FORMAT_ERROR;600 }601 }602 }603 604 private void readGraphicControlExt() {605 read(); // block size606 int packed = read(); // packed fields607 dispose = (packed & 0x1c) >> 2; // disposal method608 if (dispose == 0) {609 dispose = 1; // elect to keep old image if discretionary610 }611 transparency = (packed & 1) != 0;612 delay = readShort() * 10; // delay in milliseconds613 transIndex = read(); // transparent color index614 read(); // block terminator615 }616 617 private void readHeader() {618 String id = "";619 for (int i = 0; i < 6; i++) {620 id += (char) read();621 }622 if (!id.startsWith("GIF")) {623 status = STATUS_FORMAT_ERROR;624 return;625 }626 readLSD();627 if (gctFlag && !err()) {628 gct = readColorTable(gctSize);629 bgColor = gct[bgIndex];630 }631 }632 633 private void readImage() {634 ix = readShort(); // (sub)image position & size635 iy = readShort();636 iw = readShort();637 ih = readShort();638 int packed = read();639 lctFlag = (packed & 0x80) != 0; // 1 - local color table flag640 interlace = (packed & 0x40) != 0; // 2 - interlace flag641 // 3 - sort flag642 // 4-5 - reserved643 lctSize = 2 << (packed & 7); // 6-8 - local color table size644 if (lctFlag) {645 lct = readColorTable(lctSize); // read table646 act = lct; // make local table active647 } else {648 act = gct; // make global table active649 if (bgIndex == transIndex) {650 bgColor = 0;651 }652 }653 int save = 0;654 if (transparency) {655 save = act[transIndex];656 act[transIndex] = 0; // set transparent color if specified657 }658 if (act == null) {659 status = STATUS_FORMAT_ERROR; // no color table defined660 }661 if (err()) {662 return;663 }664 decodeImageData(); // decode pixel data665 skip();666 if (err()) {667 return;668 }669 frameCount++;670 // create new image to receive frame data671 image = Bitmap.createBitmap(width, height, Config.ARGB_4444);672 // createImage(width, height);673 setPixels(); // transfer pixel data to image674 if (gifFrame == null) {675 gifFrame = new GifFrame(image, delay);676 currentFrame = gifFrame;677 } else {678 GifFrame f = gifFrame;679 while (f.nextFrame != null) {680 f = f.nextFrame;681 }682 f.nextFrame = new GifFrame(image, delay);683 }684 // frames.addElement(new GifFrame(image, delay)); // add image to frame685 // list686 if (transparency) {687 act[transIndex] = save;688 }689 resetFrame();690 action.parseOk(true, frameCount);691 }692 693 private void readLSD() {694 // logical screen size695 width = readShort();696 height = readShort();697 // packed fields698 int packed = read();699 gctFlag = (packed & 0x80) != 0; // 1 : global color table flag700 // 2-4 : color resolution701 // 5 : gct sort flag702 gctSize = 2 << (packed & 7); // 6-8 : gct size703 bgIndex = read(); // background color index704 pixelAspect = read(); // pixel aspect ratio705 }706 707 private void readNetscapeExt() {708 do {709 readBlock();710 if (block[0] == 1) {711 // loop count sub-block712 int b1 = ((int) block[1]) & 0xff;713 int b2 = ((int) block[2]) & 0xff;714 loopCount = (b2 << 8) | b1;715 }716 } while ((blockSize > 0) && !err());717 }718 719 private int readShort() {720 // read 16-bit value, LSB first721 return read() | (read() << 8);722 }723 724 private void resetFrame() {725 lastDispose = dispose;726 lrx = ix;727 lry = iy;728 lrw = iw;729 lrh = ih;730 lastImage = image;731 lastBgColor = bgColor;732 dispose = 0;733 transparency = false;734 delay = 0;735 lct = null;736 }737 738 /**739 * Skips variable length blocks up to and including next zero length block.740 */741 private void skip() {742 do {743 readBlock();744 } while ((blockSize > 0) && !err());745 }746 }
1 import java.io.InputStream; 2 import android.content.Context; 3 import android.content.res.Resources; 4 import android.graphics.Bitmap; 5 import android.graphics.Canvas; 6 import android.graphics.Rect; 7 import android.os.Handler; 8 import android.os.Message; 9 import android.os.SystemClock; 10 import android.util.AttributeSet; 11 import android.util.Log; 12 import android.view.View; 13 14 /** 15 * GifView 16 * 本类可以显示一个gif动画,其使用方法和android的其它view(如imageview)一样。 17 * 如果要显示的gif太大,会出现OOM的问题。 18 */ 19 public class GifView extends View implements GifAction { 20 21 /** gif解码器 */ 22 private GifDecoder gifDecoder = null; 23 /** 当前要画的帧的图 */ 24 private Bitmap currentImage = null; 25 26 private boolean isRun = true; 27 28 private boolean pause = false; 29 30 private int showWidth = -1; 31 private int showHeight = -1; 32 private Rect rect = null; 33 34 private DrawThread drawThread = null; 35 36 private GifImageType animationType = GifImageType.SYNC_DECODER; 37 38 /** 39 * 解码过程中,Gif动画显示的方式 40 * 如果图片较大,那么解码过程会比较长,这个解码过程中,gif如何显示 41 * 42 * @author liao 43 * 44 */ 45 public enum GifImageType { 46 /** 47 * 在解码过程中,不显示图片,直到解码全部成功后,再显示 48 */ 49 WAIT_FINISH(0), 50 /** 51 * 和解码过程同步,解码进行到哪里,图片显示到哪里 52 */ 53 SYNC_DECODER(1), 54 /** 55 * 在解码过程中,只显示第一帧图片 56 */ 57 COVER(2); 58 59 GifImageType(int i) { 60 nativeInt = i; 61 } 62 63 final int nativeInt; 64 } 65 66 public GifView(Context context) { 67 super(context); 68 69 } 70 71 public GifView(Context context, AttributeSet attrs) { 72 this(context, attrs, 0); 73 } 74 75 public GifView(Context context, AttributeSet attrs, int defStyle) { 76 super(context, attrs, defStyle); 77 78 } 79 80 /** 81 * 设置图片,并开始解码 82 * 83 * @param gif 84 * 要设置的图片 85 */ 86 private void setGifDecoderImage(byte[] gif) { 87 if (gifDecoder != null) { 88 gifDecoder.free(); 89 gifDecoder = null; 90 } 91 gifDecoder = new GifDecoder(gif, this); 92 gifDecoder.start(); 93 } 94 95 /** 96 * 设置图片,开始解码 97 * 98 * @param is 99 * 要设置的图片100 */101 private void setGifDecoderImage(InputStream is) {102 if (gifDecoder != null) {103 gifDecoder.free();104 gifDecoder = null;105 }106 gifDecoder = new GifDecoder(is, this);107 gifDecoder.start();108 }109 110 /**111 * 以字节数据形式设置gif图片112 * 113 * @param gif114 * 图片115 */116 public void setGifImage(byte[] gif) {117 setGifDecoderImage(gif);118 }119 120 /**121 * 以字节流形式设置gif图片122 * 123 * @param is124 * 图片125 */126 public void setGifImage(InputStream is) {127 setGifDecoderImage(is);128 }129 130 /**131 * 以资源形式设置gif图片132 * 133 * @param resId134 * gif图片的资源ID135 */136 public void setGifImage(int resId) {137 Resources r = this.getResources();138 InputStream is = r.openRawResource(resId);139 setGifDecoderImage(is);140 }141 142 protected void onDraw(Canvas canvas) {143 super.onDraw(canvas);144 if (gifDecoder == null)145 return;146 if (currentImage == null) {147 currentImage = gifDecoder.getImage();148 }149 if (currentImage == null) {150 return;151 }152 int saveCount = canvas.getSaveCount();153 canvas.save();154 canvas.translate(getPaddingLeft(), getPaddingTop());155 if (showWidth == -1) {156 canvas.drawBitmap(currentImage, 0, 0, null);157 } else {158 canvas.drawBitmap(currentImage, null, rect, null);159 }160 canvas.restoreToCount(saveCount);161 }162 163 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {164 int pleft = getPaddingLeft();165 int pright = getPaddingRight();166 int ptop = getPaddingTop();167 int pbottom = getPaddingBottom();168 169 int widthSize;170 int heightSize;171 172 int w;173 int h;174 175 if (gifDecoder == null) {176 w = 1;177 h = 1;178 } else {179 w = gifDecoder.width;180 h = gifDecoder.height;181 }182 183 w += pleft + pright;184 h += ptop + pbottom;185 186 w = Math.max(w, getSuggestedMinimumWidth());187 h = Math.max(h, getSuggestedMinimumHeight());188 189 widthSize = resolveSize(w, widthMeasureSpec);190 heightSize = resolveSize(h, heightMeasureSpec);191 192 setMeasuredDimension(widthSize, heightSize);193 }194 195 /**196 * 只显示第一帧图片197 * 调用本方法后,gif不会显示动画,只会显示gif的第一帧图198 */199 public void showCover() {200 if (gifDecoder == null)201 return;202 pause = true;203 currentImage = gifDecoder.getImage();204 invalidate();205 }206 207 /**208 * 继续显示动画209 * 本方法在调用showCover后,会让动画继续显示,如果没有调用showCover方法,则没有任何效果210 */211 public void showAnimation() {212 if (pause) {213 pause = false;214 }215 }216 217 /**218 * 设置gif在解码过程中的显示方式219 * 本方法只能在setGifImage方法之前设置,否则设置无效220 * 221 * @param type222 * 显示方式223 */224 public void setGifImageType(GifImageType type) {225 if (gifDecoder == null)226 animationType = type;227 }228 229 /**230 * 设置要显示的图片的大小231 * 当设置了图片大小 之后,会按照设置的大小来显示gif(按设置后的大小来进行拉伸或压缩)232 * 233 * @param width234 * 要显示的图片宽235 * @param height236 * 要显示的图片高237 */238 public void setShowDimension(int width, int height) {239 if (width > 0 && height > 0) {240 showWidth = width;241 showHeight = height;242 rect = new Rect();243 rect.left = 0;244 rect.top = 0;245 rect.right = width;246 rect.bottom = height;247 }248 }249 250 public void parseOk(boolean parseStatus, int frameIndex) {251 if (parseStatus) {252 if (gifDecoder != null) {253 switch (animationType) {254 case WAIT_FINISH:255 if (frameIndex == -1) {256 if (gifDecoder.getFrameCount() > 1) { // 当帧数大于1时,启动动画线程257 DrawThread dt = new DrawThread();258 dt.start();259 } else {260 reDraw();261 }262 }263 break;264 case COVER:265 if (frameIndex == 1) {266 currentImage = gifDecoder.getImage();267 reDraw();268 } else if (frameIndex == -1) {269 if (gifDecoder.getFrameCount() > 1) {270 if (drawThread == null) {271 drawThread = new DrawThread();272 drawThread.start();273 }274 } else {275 reDraw();276 }277 }278 break;279 case SYNC_DECODER:280 if (frameIndex == 1) {281 currentImage = gifDecoder.getImage();282 reDraw();283 } else if (frameIndex == -1) {284 reDraw();285 } else {286 if (drawThread == null) {287 drawThread = new DrawThread();288 drawThread.start();289 }290 }291 break;292 }293 294 } else {295 Log.e("gif", "parse error");296 }297 298 }299 }300 301 private void reDraw() {302 if (redrawHandler != null) {303 Message msg = redrawHandler.obtainMessage();304 redrawHandler.sendMessage(msg);305 }306 }307 308 private Handler redrawHandler = new Handler() {309 public void handleMessage(Message msg) {310 invalidate();311 }312 };313 314 /**315 * 动画线程317 * @author liao319 */320 private class DrawThread extends Thread {321 public void run() {322 if (gifDecoder == null) {323 return;324 }325 while (isRun) {326 if (pause == false) {327 // if(gifDecoder.parseOk()){ 328 GifFrame frame = gifDecoder.next();329 currentImage = frame.image;330 long sp = frame.delay;331 if (redrawHandler != null) {332 Message msg = redrawHandler.obtainMessage();333 redrawHandler.sendMessage(msg);334 SystemClock.sleep(sp);335 } else {336 break;337 }338 // }else{339 // currentImage = gifDecoder.getImage();340 // break;341 // }342 } else {343 SystemClock.sleep(10);344 }345 }346 }347 }348 349 }
以上是Gif用到的所有类库。
以下是该控件的使用方法。
1 27 8 14 15 22 23 30 31
1 import android.app.Activity; 2 import android.os.Bundle; 3 import android.view.View; 4 import android.view.View.OnClickListener; 6 import com.test.gifview.GifView; 7 import com.test.gifview.GifView.GifImageType; 8 9 public class TestAction extends Activity implements OnClickListener {10 11 private GifView gf1;12 private GifView gf2;13 private boolean f = true;14 15 public void onCreate(Bundle icicle) {16 super.onCreate(icicle);17 // Log.d("dddddddddd",Environment.getRootDirectory().getAbsolutePath());18 // LinearLayout ll = new LinearLayout(this);19 // LayoutParams la = new LayoutParams(LayoutParams.FILL_PARENT,20 // LayoutParams.FILL_PARENT);21 //22 // ll.setLayoutParams(la);23 // gf1 = new GifView(this);24 // gf2 = new GifView(this);25 //26 // gf1.setGifImage(R.drawable.gif1);27 // gf2.setGifImage(R.drawable.gif2);28 //29 // ll.addView(gf1);30 // ll.addView(gf2);31 //32 // setContentView(ll);33 34 setContentView(R.layout.gif);35 gf1 = (GifView) findViewById(R.id.gif1);36 // 设置Gif图片源37 gf1.setGifImage(R.drawable.big_mm);38 // 添加监听器39 gf1.setOnClickListener(this);40 41 gf2 = (GifView) findViewById(R.id.gif2);42 // 设置加载方式:先加载后显示、边加载边显示、只显示第一帧再显示43 gf2.setGifImageType(GifImageType.COVER);44 // 设置显示的大小,拉伸或者压缩45 gf2.setShowDimension(300, 300);46 // 设置Gif图片源47 gf2.setGifImage(R.drawable.a);48 // 添加监听器49 // gf2.setOnClickListener(this);50 }51 52 public void onClick(View v) {53 if (f) {54 // 点击停止动画55 gf1.showCover();56 f = false;57 } else {58 // 点击播放动画59 gf1.showAnimation();60 f = true;61 }62 }63 }