5三、Gif 控件GifView 的使用,播放gif圖片

GifView 是一個爲了解決android中如今沒有直接顯示gif的view,只能經過mediaplay來顯示這個問題的項目,其用法和 ImageView同樣,支持gif圖片。可監視GIF是否加載成功。java

GifView的功能: 播放Gif圖片 Gif動畫監聽android

Android GifView 的用法:canvas

GifAction.java 觀察者類,監視GIF是否加載成功
GifFrame.java 裏面三個成員:當前圖片、延時、下張Frame的連接。
GifDecoder.java 解碼線程類
GifView.java 主類,包括經常使用方法,如GifView構造方法、設置圖片源、延遲、繪製等。app

 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  * @return 120 */ 121 public int getStatus() { 122 return status; 123  } 124 125 /** 126  * 解碼是否成功,成功返回true 127  * @return 成功返回true,不然返回false 128 */ 129 public boolean parseOk() { 130 return status == STATUS_FINISH; 131  } 132 133 /** 134  * 取某幀的延時時間 135  * @param n 136  * 第幾幀 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  * @return 153 */ 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  * @return 177 */ 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 code 189 if (lastDispose > 0) { 190 if (lastDispose == 3) { 191 // use image before last 192 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 pixels 202 if (lastDispose == 2) { 203 // fill last image rect area with background color 204 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 destination 220 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 dest 248 int dlim = dx + iw; // end of dest line 249 if ((k + width) < dlim) { 250 dlim = k + width; // past dest edge 251  } 252 int sx = i * iw; // start of line in source 253 while (dx < dlim) { 254 // map color and insert in destination 255 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 n 271  * 幀數 272  * @return 可畫的圖片,若是沒有此幀或者出錯,返回null 273 */ 274 public Bitmap getFrameImage(int n) { 275 GifFrame frame = getFrame(n); 276 if (frame == null) 277 return null; 278 else 279 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 n 295  * 幀數 296  * @return 297 */ 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 array 388 } 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 code 437 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 pixels 487 } 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 checks 550 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 blocks 564 boolean done = false; 565 while (!(done || err())) { 566 int code = read(); 567 switch (code) { 568 case 0x2C: // image separator 569 readImage(); 570 break; 571 case 0x21: // extension 572 code = read(); 573 switch (code) { 574 case 0xf9: // graphics control extension 575 readGraphicControlExt(); 576 break; 577 case 0xff: // application extension 578 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 care 587 } 588 break; 589 default: // uninteresting extension 590 skip(); 591 } 592 break; 593 case 0x3b: // terminator 594 done = true; 595 break; 596 case 0x00: // bad byte, but keep going and see what happens 597 break; 598 default: 599 status = STATUS_FORMAT_ERROR; 600 } 601 } 602 } 603 604 private void readGraphicControlExt() { 605 read(); // block size 606 int packed = read(); // packed fields 607 dispose = (packed & 0x1c) >> 2; // disposal method 608 if (dispose == 0) { 609 dispose = 1; // elect to keep old image if discretionary 610 } 611 transparency = (packed & 1) != 0; 612 delay = readShort() * 10; // delay in milliseconds 613 transIndex = read(); // transparent color index 614 read(); // block terminator 615 } 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 & size 635 iy = readShort(); 636 iw = readShort(); 637 ih = readShort(); 638 int packed = read(); 639 lctFlag = (packed & 0x80) != 0; // 1 - local color table flag 640 interlace = (packed & 0x40) != 0; // 2 - interlace flag 641 // 3 - sort flag 642 // 4-5 - reserved 643 lctSize = 2 << (packed & 7); // 6-8 - local color table size 644 if (lctFlag) { 645 lct = readColorTable(lctSize); // read table 646 act = lct; // make local table active 647 } else { 648 act = gct; // make global table active 649 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 specified 657 } 658 if (act == null) { 659 status = STATUS_FORMAT_ERROR; // no color table defined 660 } 661 if (err()) { 662 return; 663 } 664 decodeImageData(); // decode pixel data 665 skip(); 666 if (err()) { 667 return; 668 } 669 frameCount++; 670 // create new image to receive frame data 671 image = Bitmap.createBitmap(width, height, Config.ARGB_4444); 672 // createImage(width, height); 673 setPixels(); // transfer pixel data to image 674 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 frame 685 // list 686 if (transparency) { 687 act[transIndex] = save; 688 } 689 resetFrame(); 690 action.parseOk(true, frameCount); 691 } 692 693 private void readLSD() { 694 // logical screen size 695 width = readShort(); 696 height = readShort(); 697 // packed fields 698 int packed = read(); 699 gctFlag = (packed & 0x80) != 0; // 1 : global color table flag 700 // 2-4 : color resolution 701 // 5 : gct sort flag 702 gctSize = 2 << (packed & 7); // 6-8 : gct size 703 bgIndex = read(); // background color index 704 pixelAspect = read(); // pixel aspect ratio 705 } 706 707 private void readNetscapeExt() { 708 do { 709 readBlock(); 710 if (block[0] == 1) { 711 // loop count sub-block 712 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 first 721 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<br>  16  * 本類能夠顯示一個gif動畫,其使用方法和android的其它view(如imageview)同樣。<br>  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動畫顯示的方式<br>  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 gif 114  * 圖片 115 */ 116 public void setGifImage(byte[] gif) { 117  setGifDecoderImage(gif); 118  } 119 120 /** 121  * 以字節流形式設置gif圖片 122  * 123  * @param is 124  * 圖片 125 */ 126 public void setGifImage(InputStream is) { 127  setGifDecoderImage(is); 128  } 129 130 /** 131  * 以資源形式設置gif圖片 132  * 133  * @param resId 134  * gif圖片的資源ID 135 */ 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  * 只顯示第一幀圖片<br> 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  * 繼續顯示動畫<br> 209  * 本方法在調用showCover後,會讓動畫繼續顯示,若是沒有調用showCover方法,則沒有任何效果 210 */ 211 public void showAnimation() { 212 if (pause) { 213 pause = false; 214  } 215  } 216 217 /** 218  * 設置gif在解碼過程當中的顯示方式<br> 219  * <strong>本方法只能在setGifImage方法以前設置,不然設置無效</strong> 220  * 221  * @param type 222  * 顯示方式 223 */ 224 public void setGifImageType(GifImageType type) { 225 if (gifDecoder == null) 226 animationType = type; 227  } 228 229 /** 230  * 設置要顯示的圖片的大小<br> 231  * 當設置了圖片大小 以後,會按照設置的大小來顯示gif(按設置後的大小來進行拉伸或壓縮) 232  * 233  * @param width 234  * 要顯示的圖片寬 235  * @param height 236  * 要顯示的圖片高 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用到的全部類庫。函數

   如下是該控件的使用方法。oop

 1 <?xml version="1.0" encoding="utf-8"?>  2 <LinearLayout  3 xmlns:android="http://schemas.android.com/apk/res/android"  4  android:layout_width="fill_parent"  5  android:layout_height="fill_parent"  6  android:orientation="vertical" >  7  8 <com.test.gifview.GifView  9 android:id="@+id/gif1" 10  android:layout_width="wrap_content" 11  android:layout_height="wrap_content" 12  android:enabled="false" 13  android:paddingRight="14px" /> 14 15 <TextView 16 android:id="@+id/tsxt" 17  android:layout_width="wrap_content" 18  android:layout_height="wrap_content" 19  android:enabled="false" 20  android:paddingRight="4px" 21  android:text="click the Angel" /> 22 23 <com.test.gifview.GifView 24 android:id="@+id/gif2" 25  android:layout_width="wrap_content" 26  android:layout_height="wrap_content" 27  android:enabled="false" 28  android:paddingLeft="14px" 29  android:paddingTop="4px" /> 30 31 </LinearLayout>
 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 }

 https://code.google.com/archive/p/gifview/downloads動畫

相關文章
相關標籤/搜索