Movie 類
官方對這個類連一句介紹都沒有,並且所有的方法也沒有一行注釋,可見多么不受重視!
package android.graphics;
直接繼承自Object,
直接繼承自Object的基本上都是
工具類。
Android的ImageView無法直接加載Gif圖片,鑒於此,Android社區開發者為解決此問題貢獻了很多解決方案,其中一種比較簡易的做法是通過Android中的Movie類把一個gif圖片當作一個原始的資源加載到Movie,然后Movie將其解析為Movie幀進行加載。
Movie其實管理着GIF動畫中的多個幀,只需要通過 setTime() 一下就可以讓它在draw()的時候繪出相應的那幀圖像,通過當前時間與duration之間的換算關系,便可實現GIF動起來的效果。
對於比較小的
gif圖片使用此方法
還是可以的,要是大的話,建議還是把gif圖片轉換成一幀一幀的png圖片,然后通過animation播放。
簡單的利用Movie播放GIF圖的控件
setContentView(new CustomGifView(this, R.drawable.ic_launcher)); //顯示普通圖片
setContentView(new CustomGifView(this, R.drawable.gif1)); //顯示gif動圖
/**
* 自定義可以循環播放gif動畫的View,可以像使用其他控件一樣使用
* @author 白乾濤
*/
public class CustomGifView extends View {
private Movie mMovie;
private long mMovieStart;
private int resId;
public CustomGifView(Context context, int resId) {
super(context);
this.resId = resId;
setLayerType(View.LAYER_TYPE_SOFTWARE, null);//必須關閉硬件加速
mMovie = Movie.decodeStream(getResources().openRawResource(resId));//創建Movie對象
}
public void onDraw(Canvas canvas) {
long now = SystemClock.uptimeMillis();//系統當前時刻
//第一次播放
if (mMovieStart == 0) mMovieStart = now;//動畫開始的時間
if (mMovie != null) {
int dur = mMovie.duration();//動畫持續的時間,也就是完成一次動畫的時間
if (dur == 0) dur = 1000;
int relTime = (int) ((now - mMovieStart) % dur);//注意這是取余操作,這才能算出當前這次重復播放的第一幀的時間
mMovie.setTime(relTime);//設置相對本次播放第一幀時間,根據這個時間來決定顯示第幾幀
mMovie.draw(canvas, 0, 0);
invalidate();
} else {//如果指定的資源不是gif圖片,也就是說是普通的圖片,則需要手動繪制此圖片
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), resId), getMatrix(), new Paint());
}
}
}
Movie 類的 API
- static Movie decodeByteArray(byte[] data, int offset, int length)
- static Movie decodeFile(String pathName)
- static Movie decodeStream(InputStream is)
- void draw(Canvas canvas, float x, float y, Paint paint)
- void draw(Canvas canvas, float x, float y)
- int duration()
- int height()
- boolean isOpaque()
- boolean setTime(int relativeMilliseconds)
- int width()
開源庫 android-gif-drawable
底層解碼使用C實現,極大的提高了解碼效率,同時很大程度上避免了OOM。
Views and Drawable for displaying animated GIFs on Android
Bundled GIFLib via
JNI is used to render frames. This way should be more
efficient than
WebView or
Movie classes.
Requirements
- Android 2.3+ (API level 9+)
- for GifTextureView Android 4.0+ (API level 14+) and hardware-accelerated rendering渲染
- for GifTexImage2D OpenGL ES 2.0+
Building from source
- Android NDK needed to compile native sources
配置build.gradle
Insert the following dependency to build.gradle file of your project.
dependencies {
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.6'
}
buildscript {
repositories {
mavenCentral()
}
}
allprojects {
repositories {
mavenCentral()
}
}
XML中使用
The simplest way is to use
GifImageView or
GifImageButton like a normal ImageView:
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gif1"
android:src="@drawable/gif2"/>
If drawables declared by
android:src
and/or
android:background are GIF files then they will be automatically recognized as GifDrawables and animated. If given drawable is not a GIF then mentioned Views work like plain平常的 ImageView and ImageButton.
GifTextView allows you to use GIFs as compound復合的 drawables and background.
<pl.droidsonroids.gif.GifTextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gif1"
android:drawableTop="@drawable/gif2"/>
代碼中構造GifDrawable
GifImageView, GifImageButton and GifTextView have also hooks for
setters implemented. So animated GIFs can be set by calling
setImageResource(int resId) and
setBackgroundResource(int resId)
GifDrawable can be constructed directly from various sources:
void constructGifDrawable() throws IOException {
//asset file
GifDrawable gifFromAssets = new GifDrawable(getAssets(), "gif1.gif");
//resource (drawable or raw)
GifDrawable gifFromResource = new GifDrawable(getResources(), R.drawable.gif1);
//Uri
ContentResolver contentResolver = null; //can be null for file:// Uris
GifDrawable gifFromUri = new GifDrawable(contentResolver, null);//gifUri
//byte array
byte[] rawGifBytes = null;
GifDrawable gifFromBytes = new GifDrawable(rawGifBytes);
//FileDescriptor
FileDescriptor fd = new RandomAccessFile("/path/anim.gif", "r").getFD();
GifDrawable gifFromFd = new GifDrawable(fd);
//file path
GifDrawable gifFromPath = new GifDrawable("/path/anim.gif");
//file
File gifFile = new File(getFilesDir(), "gif1.gif");
GifDrawable gifFromFile = new GifDrawable(gifFile);
//AssetFileDescriptor
AssetFileDescriptor afd = getAssets().openFd("gif1.gif");
GifDrawable gifFromAfd = new GifDrawable(afd);
//InputStream (it must support marking)
InputStream sourceIs = null;
BufferedInputStream bis = new BufferedInputStream(sourceIs, 1024);//GIF_LENGTH
GifDrawable gifFromStream = new GifDrawable(bis);
//direct ByteBuffer
ByteBuffer rawGifByteBuffer = null;
GifDrawable gifFromByteBuffer = new GifDrawable(rawGifByteBuffer);
}
InputStreams are closed automatically in finalizer if GifDrawable is no longer needed so you don't need to explicitly明確的 close them. Calling
recycle() will also close underlying潛在的 input source.
Note that all input sources need to have ability to rewind倒回 to the beginning. It is required to correctly play animated GIFs (where animation is repeatable) since subsequent隨后的 frames are decoded on demand from source.
動畫過程控制 Animation control
GifDrawable implements an
Animatable and
MediaPlayerControl so you can use its methods and more:
- stop() - stops the animation, can be called from any thread
- start() - starts the animation, can be called from any thread
- isRunning() - returns whether animation is currently running or not
- reset() - rewinds the animation, does not restart stopped one
- setSpeed(float factor) - sets new animation speed factor, eg. passing 2.0f will double the animation speed
- seekTo(int position) - seeks animation (within current loop) to given position (in milliseconds)
- getDuration() - returns duration of one loop of the animation
- getCurrentPosition() - returns elapsed time from the beginning of a current loop of animation
使用 MediaPlayerControl
Standard controls for a MediaPlayer (like in
VideoView) can be used to control GIF animation and show its current progress.
Just set GifDrawable as MediaPlayer on your MediaController like this:
@BindView(R.id.gif) GifImageView gifView;
android.widget.MediaController mc;
mc = new MediaController(this);
mc.setMediaPlayer((pl.droidsonroids.gif.GifDrawable) gifView.getDrawable());
mc.setAnchorView(gifView);
mc.show();
獲取GIF元數據
Retrieving GIF metadata
- getLoopCount() - returns a loop count as defined in NETSCAPE 2.0 extension
- getNumberOfFrames() - returns number of frames (at least 1)
- getComment() - returns comment text (null if GIF has no comment)
- getFrameByteCount() - returns minimum number of bytes that can be used to store pixels of the single frame
- getAllocationByteCount() - returns size (in bytes) of the allocated memory used to store pixels of given GifDrawable
- getInputSourceByteCount() - returns length (in bytes) of the backing input data
- toString() - returns human readable information about image size and number of frames (intended for debugging purpose)
一個GifDrawable用在多個View上
Associating single GifDrawable instance
with multiple Views:
Normally single GifDrawable instance associated with multiple Views will
animate only on the last one. To solve that create
MultiCallback instance,
add Views to it and set callback for given drawable, eg.:
MultiCallback multiCallback = new MultiCallback();
imageView.setImageDrawable(gifDrawable);
multiCallback.addView(imageView);
anotherImageView.setImageDrawable(gifDrawable);
multiCallback.addView(anotherImageView);
gifDrawable.setCallback(multiCallback);
高級API
Advanced
recycle() - provided to
speed up freeing memory (like in android.graphics.Bitmap)
isRecycled() - checks whether drawable is recycled
getError() - returns last error details
開源庫 Cutta/GifView
Library for playing gifs on Android
Simple android view to display gifs efficiently高效的. You can start, pause and stop gifView.
Inspired by靈感來自 sbakhtiarov/gif-movie-view
這個自定義的View其實主要還是使用了
android.graphics.Movie 這個類。
去看源碼時,發現就一個獨桿司令GifView,API也就下面幾個:

AS中使用
Add these lines on
top-level build file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
repositories {
maven {
url "https://jitpack.io"
}
}
compile 'com.github.Cutta:GifView:1.1'
布局和代碼中設置:
xmlns:custom="http://schemas.android.com/apk/res-auto"
<com.cunoraz.gifview.library.GifView
android:id="@+id/gif"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerInParent="true"
custom:gif="@drawable/gif1"/>
GifView gifView = (GifView) view.findViewById(R.id.gif);
gifView.pause(); //默認為自動播放,可以手動設置 custom:paused="true"
Eclipse中使用
1、把
獨桿司令GifView拷到項目中
2
、把自定義屬性拷到attrs.xml中
<declare-styleable name="GifView">
<attr name="gif" format="reference" />
<attr name="paused" format="boolean" />
</declare-styleable>
3
、在布局和代碼中使用
xmlns:custom="http://schemas.android.com/apk/res/com.bqt"
<com.bqt.GifView
android:id="@+id/gif"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:gif="@drawable/gif" />
沒啥好說的,簡單實用。
附件列表