Implement custom View to display Animated GIF

It's a improved version of the example "Play animated GIF using android.graphics.Movie, with Movie.decodeStream(InputStream)".


- Add function of Run/Stop, and Repeat setting
- Instead of disable hardware acceleration in AndroidManifest.xml, the custom AnimatedGifView disable hardware acceleration by calling setLayerType(), for API Level 11.

Our custom view, AnimatedGifView.gif
package com.example.androidgif;

import java.io.InputStream;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;

public class AnimatedGifView extends View {

private InputStream gifInputStream;
private Movie gifMovie;
private int movieWidth, movieHeight;
private long movieDuration;
private long movieRunDuration;
private long lastTick;
private long nowTick;

private boolean repeat = true;
private boolean running = true;

public void setRepeat(boolean r) {
repeat = r;
}

public void setRunning(boolean r) {
running = r;
}

public AnimatedGifView(Context context) {
super(context);
init(context);
}

public AnimatedGifView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public AnimatedGifView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

private void init(Context context) {

// Turn OFF hardware acceleration
// API Level 11
setLayerType(View.LAYER_TYPE_SOFTWARE, null);

setFocusable(true);
gifInputStream = context.getResources().openRawResource(
R.drawable.android_er);

gifMovie = Movie.decodeStream(gifInputStream);
movieWidth = gifMovie.width();
movieHeight = gifMovie.height();
movieDuration = gifMovie.duration();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(movieWidth, movieHeight);
}

public int getMovieWidth() {
return movieWidth;
}

public int getMovieHeight() {
return movieHeight;
}

public long getMovieDuration() {
return movieDuration;
}

@Override
protected void onDraw(Canvas canvas) {

if(gifMovie == null){
return;
}

nowTick = android.os.SystemClock.uptimeMillis();
if (lastTick == 0) { // first time
movieRunDuration = 0;
}else{
if(running){
movieRunDuration += nowTick-lastTick;
if(movieRunDuration > movieDuration){
if(repeat){
movieRunDuration = 0;
}else{
movieRunDuration = movieDuration;
}
}
}
}

gifMovie.setTime((int)movieRunDuration);
gifMovie.draw(canvas, 0, 0);

lastTick = nowTick;
invalidate();

}
}

MainActivity.java
package com.example.androidgif;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.ToggleButton;

public class MainActivity extends ActionBarActivity {

TextView textViewInfo;
AnimatedGifView gifView;

CheckBox cbRepeat;
ToggleButton tbRun;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

gifView = (AnimatedGifView) findViewById(R.id.gifview);
textViewInfo = (TextView) findViewById(R.id.textinfo);

String stringInfo = "";
stringInfo += "Duration: " + gifView.getMovieDuration() + "\n";
stringInfo += "W x H: " + gifView.getMovieWidth() + " x "
+ gifView.getMovieHeight() + "\n";

textViewInfo.setText(stringInfo);

cbRepeat = (CheckBox)findViewById(R.id.repeat);
cbRepeat.setOnCheckedChangeListener(new OnCheckedChangeListener(){

@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
gifView.setRepeat(isChecked);
}});

tbRun = (ToggleButton)findViewById(R.id.run);
tbRun.setOnCheckedChangeListener(new OnCheckedChangeListener(){

@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
gifView.setRunning(isChecked);
}});
}

}

activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context="com.example.androidgif.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<CheckBox
android:id="@+id/repeat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Repeat"
android:checked="true"/>
<ToggleButton
android:id="@+id/run"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOn="Stop"
android:textOff="Run"
android:checked="true"/>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/android_er"
/>

<com.example.androidgif.AnimatedGifView
android:id="@+id/gifview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

<TextView
android:id="@+id/textinfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="info..." />

</LinearLayout>



download filesDownload the files.