1. 程式人生 > >整合大量開源庫專案(八)可以載入Gif動畫的GifImageView

整合大量開源庫專案(八)可以載入Gif動畫的GifImageView

上週大多數時間都是根據興起,想到什麼做什麼寫了幾個自定義控制元件,把Soyi丟在那沒怎麼動,今天就把寫的東西整合進來,順便把SOyi”個人研發的結構理一下”。

先上一下今天整合之後的效果,以及新加進來的幾個庫:

這裡寫圖片描述

按照慣例,貼一下Gradle的配置:

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'cn.pedant.sweetalert:library:1.3'
compile 'com.apkfuns.logutils:library:1.0.6' compile 'com.nineoldandroids:library:2.4.0' compile 'com.squareup.okhttp:okhttp:2.7.0' compile 'commons-io:commons-io:2.4' compile 'com.ikimuhendis:ldrawer:0.1' compile 'com.dodola:listviewext:1.0' compile 'com.bm.photoview:library:1.3.6'
compile 'com.lsjwzh:materialloadingprogressbar:0.5.8-RELEASE' compile 'net.frakbot:jumpingbeans:1.3.0' compile 'com.bigkoo:convenientbanner:1.1.4' compile files('libs/universal-image-loader-1.9.4.jar') compile 'com.google.code.gson:gson:2.5' compile 'com.android.support:recyclerview-v7:23.1.+'
compile 'com.felipecsl:gifimageview:2.0.0' compile 'com.android.support:support-annotations:23.1.1' }

是不是加進來的東西越來越多了? 之後還會繼續新增(當然,實際專案中不建議使用過多的第三方框架,畢竟大框架的個別功能你是用不到的,而自己卻載入了那麼多內容,容易加大apk無謂的容積)

這一篇我們加了什麼,講些什麼??

GifImageView和簡單的程式碼梳理。(有一定工作經歷的小夥伴可以不看第二部分,原始碼還是在最下面)

通常為我們的ImageView只支援普通的靜態圖片的展現(png,jpg等),如果是動圖什麼的就需要我們自己寫了,但是有人給我們寫好了,為何不用呢?

樓主這邊為大家簡單的分析下這個庫的實現。

public class GifImageView extends ImageView implements Runnable

↑ 繼承於ImageView繼承Runnable,也就是說我們的各種繪畫的操作其實是在多執行緒的環境下進行的。

 private final Runnable updateResults = new Runnable() {
    @Override
    public void run() {
      if (tmpBitmap != null && !tmpBitmap.isRecycled()) {
        setImageBitmap(tmpBitmap);
      }
    }
  };

判斷暫時的tmpBitmap 不為空,並且沒有被釋放,然後給imageview設定這張圖片,這個方法在handle中被多次傳遞。

 private final Runnable cleanupRunnable = new Runnable() {
    @Override
    public void run() {
      if (tmpBitmap != null && !tmpBitmap.isRecycled()) {
        tmpBitmap.recycle();
      }
      tmpBitmap = null;
      gifDecoder = null;
      animationThread = null;
      shouldClear = false;
    }
  };

↑ 回收tmpBitmap 並且,清空一系列引數。

  @Override public void run() {
    if (shouldClear) {
      handler.post(cleanupRunnable);
      return;
    }

    final int n = gifDecoder.getFrameCount();
    do {
      for (int i = 0; i < n; i++) {
        if (!animating) {
          break;
        }
        //milliseconds spent on frame decode
        long frameDecodeTime = 0;
        try {
          long before = System.nanoTime();
          tmpBitmap = gifDecoder.getNextFrame();
          frameDecodeTime = (System.nanoTime() - before) / 1000000;
          if (frameCallback != null) {
            tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap);
          }

          if (!animating) {
            break;
          }
          handler.post(updateResults);
        } catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
          Log.w(TAG, e);
        }
        if (!animating) {
          break;
        }
        gifDecoder.advance();
        try {
          int delay = gifDecoder.getNextDelay();
          // Sleep for frame duration minus time already spent on frame decode
          // Actually we need next frame decode duration here,
          // but I use previous frame time to make code more readable
          delay -= frameDecodeTime;
          if (delay > 0) {
            Thread.sleep(framesDisplayDuration > 0 ? framesDisplayDuration : delay);
          }
        } catch (final Exception e) {
          // suppress any exception
          // it can be InterruptedException or IllegalArgumentException
        }
      }
    } while (animating);
  }

主要實現的run方法,先判斷是否clear,預設false.(也就是animationThread 這條工作執行緒的行為)

然後獲取從檔案讀取的幀的數目(這邊只解釋下主實現類的內容,Gif其實就是幀動畫)

接下來迴圈,開始更替圖片操作(理論上一幀一畫面)

判斷如果正在動畫效果中,就不進行在此迴圈操作(因為可能出現手動呼叫startAnimation()的可能)

接下來就是一幀持續多久,然後替換,然後直到最後一幀的顯示結束,再繼續。

整個包大概 10來個類,大家可以自己有時間詳細讀取。

總結:現對於https://github.com/frapontillo/ImageViewEx的實現屬於比較輕量級的了,畢竟簡單實用是大家更喜歡的。實現大致就是根據傳入的陣列進行計算,把每一幀的動畫進行迭代的呈現在UI介面上,然後在呼叫StopAnimation()或者clear()之前會形成一個環。當然這樣的頻繁刷UI介面還是會有一定的效能影響,看你怎麼使用了。

接下來再說下“個人研發”模組,那這是什麼東西呢?
很顯然看上去就是一個ListView套著一個ListView然後第一層的ListView的選擇會讓第二層的內容大不相同,像這樣。

這裡寫圖片描述

那麼難道,我去寫一大堆新的xml麼?

No,找共同點,遵循OOP會發現共同點。

統一的item,統一的呈現頁面(一個Title,1個展示圖,一個文字描述,一個超級連結)

那就是基本的MVC模式我們在 View,Controller層面的內容是大致相同的那麼就只要在Model層做出一些改變就好了,那麼從頭到尾 我 只需要一個佈局檔案,像這樣

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".Activity.CodeActivityPro.CodeActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/codeListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"
        android:scrollbars="none"
        android:layoutAnimation="@anim/code_item_anim" />
</RelativeLayout>

然後就是展示頁面,像這樣

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="soyi.pro.com.soyi.Activity.CodeActivityPro.ShowCodeViewActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.felipecsl.gifimageview.library.GifImageView
            android:id="@+id/showCodeViewImage"
            android:layout_gravity="center"
            android:layout_width="350dp"
            android:layout_height="450dp"
            android:src="@drawable/tempimage"/>

        <TextView
            android:layout_marginTop="30dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="載入中..."
            android:textSize="20dp"
            android:id="@+id/jumpText"
            android:layout_alignBottom="@id/showCodeViewImage"
            android:layout_gravity="center"/>
    </LinearLayout>
</ScrollView>

其他一系列就從arrays.xml裡面獲取內容就好了當然,傳遞通過intent.putExtra,或者如果要2層都做在一個頁面裡那就設定點靜態變數什麼的,記錄使用者的選擇吧。

如何讓你的TextView可以變為連結?

 textView.setText(Html.fromHtml(getIntent().getStringExtra("CodeActivityToShowCodeActivityMSG")  +"<br><a href=\""+getIntent().getStringExtra("CodeActivityToShowCodeActivityGitUrl")+"\">點選連結可訪問專案地址</a>"));
 textView.setMovementMethod(LinkMovementMethod.getInstance());

記得點個贊哦!

這裡寫圖片描述