- 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 the files.
Great work. I took just the Animated GIF class, and the example of how to include in the layout XML, added a GIF resource, and it worked. I also modified the code to have a gifResourceId property in the XML, and have the resource loaded that way, rather than in the class itself. Thanks for sharing.
ReplyDeleteHi Christopher,
ReplyDeleteCan you please share your code with us?
mail it to 716sasuke@gmail.com
Thanks.
Thank you very much for the great post. Do you know by the chance how to alter the size of the gif? Lets say I would like to enlarge it a little bit?
ReplyDeleteThank you again!
Hi there!
ReplyDeleteVery useful post. I noticed a lot of people asking for "how to increase the size" - and, having been forced to figure it out, thought I'd share.
Without all the particulars, you need to, before 'invalidate();' in your 'onDraw':
final int savedState = canvas.save();
/* passed into scale are multipliers. So, need to pass in the appropriate factor. Unless you want your gif to be skewed, use the same factor twice (it's a float). */
canvas.scale(scaler, scaler);
gifMovie.draw(canvas, 0, 0);
canvas.restoreToCount(savedState);
Cheers, and thanks again!
Somebody tried to play gif in reverse order(from end to start)? Performance is terrible. I don't know why bug it seems like something with inner Movie class implementation.
ReplyDelete