zoukankan      html  css  js  c++  java
  • 53、Gif 控件GifView 的使用,播放gif图片

    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      * @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用到的所有类库。

       以下是该控件的使用方法。

     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

  • 相关阅读:
    Linux Centos7配置mysql8.0数据库
    Linux Centos7配置ftp服务器
    线程池工具ThreadPoolExecutor
    Layui 实现input 输入和选择
    canvas验证码实现
    弹性布局flex 介绍
    java EE 新手入门了解
    java web工程web.xml介绍
    js 数组常用的一些方法
    详解为什么需要重写hashcode 和 equals 方法
  • 原文地址:https://www.cnblogs.com/androidsj/p/4973794.html
Copyright © 2011-2022 走看看