Android Open Source - gif-movie-view Gif Movie View






From Project

Back to project page gif-movie-view.

License

The source code is released under:

Copyright (c) 2013, Sergey Bakhtiarov All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are me...

If you think the Android project gif-movie-view listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.basv.gifmoviewview.widget;
/*from   w  w  w.  java  2  s.  c  om*/
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import com.basv.gifmoviewview.R;

/**
 * This is a View class that wraps Android {@link Movie} object and displays it.
 * You can set GIF as a Movie object or as a resource id from XML or by calling
 * {@link #setMovie(Movie)} or {@link #setMovieResource(int)}.
 * <p>
 * You can pause and resume GIF animation by calling {@link #setPaused(boolean)}.
 * <p>
 * The animation is drawn in the center inside of the measured view bounds.
 * 
 * @author Sergey Bakhtiarov
 */

public class GifMovieView extends View {

  private static final int DEFAULT_MOVIEW_DURATION = 1000;

  private int mMovieResourceId;
  private Movie mMovie;

  private long mMovieStart;
  private int mCurrentAnimationTime = 0;
  
  /**
   * Position for drawing animation frames in the center of the view.
   */
  private float mLeft;
  private float mTop;

  /**
   * Scaling factor to fit the animation within view bounds.
   */
  private float mScale;

  /**
   * Scaled movie frames width and height.
   */
  private int mMeasuredMovieWidth;
  private int mMeasuredMovieHeight;

  private volatile boolean mPaused = false;
  private boolean mVisible = true;

  public GifMovieView(Context context) {
    this(context, null);
  }

  public GifMovieView(Context context, AttributeSet attrs) {
    this(context, attrs, R.styleable.CustomTheme_gifMoviewViewStyle);
  }

  public GifMovieView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    setViewAttributes(context, attrs, defStyle);
  }

  @SuppressLint("NewApi")
  private void setViewAttributes(Context context, AttributeSet attrs, int defStyle) {

    /**
     * Starting from HONEYCOMB have to turn off HW acceleration to draw
     * Movie on Canvas.
     */
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GifMoviewView, defStyle,
        R.style.Widget_GifMoviewView);

    mMovieResourceId = array.getResourceId(R.styleable.GifMoviewView_gif, -1);
    mPaused = array.getBoolean(R.styleable.GifMoviewView_paused, false);

    array.recycle();

    if (mMovieResourceId != -1) {
      mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
    }
  }

  public void setMovieResource(int movieResId) {
    this.mMovieResourceId = movieResId;
    mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
    requestLayout();
  }

  public void setMovie(Movie movie) {
    this.mMovie = movie;
    requestLayout();
  }

  public Movie getMovie() {
    return mMovie;
  }

  public void setMovieTime(int time) {
    mCurrentAnimationTime = time;
    invalidate();
  }

  public void setPaused(boolean paused) {
    this.mPaused = paused;

    /**
     * Calculate new movie start time, so that it resumes from the same
     * frame.
     */
    if (!paused) {
      mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime;
    }

    invalidate();
  }

  public boolean isPaused() {
    return this.mPaused;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    if (mMovie != null) {
      int movieWidth = mMovie.width();
      int movieHeight = mMovie.height();

      /*
       * Calculate horizontal scaling
       */
      float scaleH = 1f;
      int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);

      if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
        int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
        if (movieWidth > maximumWidth) {
          scaleH = (float) movieWidth / (float) maximumWidth;
        }
      }

      /*
       * calculate vertical scaling
       */
      float scaleW = 1f;
      int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);

      if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
        int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (movieHeight > maximumHeight) {
          scaleW = (float) movieHeight / (float) maximumHeight;
        }
      }

      /*
       * calculate overall scale
       */
      mScale = 1f / Math.max(scaleH, scaleW);

      mMeasuredMovieWidth = (int) (movieWidth * mScale);
      mMeasuredMovieHeight = (int) (movieHeight * mScale);

      setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);

    } else {
      /*
       * No movie set, just set minimum available size.
       */
      setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
    }
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    /*
     * Calculate left / top for drawing in center
     */
    mLeft = (getWidth() - mMeasuredMovieWidth) / 2f;
    mTop = (getHeight() - mMeasuredMovieHeight) / 2f;
    
    mVisible = getVisibility() == View.VISIBLE;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    if (mMovie != null) {
      if (!mPaused) {
        updateAnimationTime();
        drawMovieFrame(canvas);
        invalidateView();
      } else {
        drawMovieFrame(canvas);
      }
    }
  }
  
  /**
   * Invalidates view only if it is visible.
   * <br>
   * {@link #postInvalidateOnAnimation()} is used for Jelly Bean and higher.
   * 
   */
  @SuppressLint("NewApi")
  private void invalidateView() {
    if(mVisible) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        postInvalidateOnAnimation();
      } else {
        invalidate();
      }
    }
  }

  /**
   * Calculate current animation time
   */
  private void updateAnimationTime() {
    long now = android.os.SystemClock.uptimeMillis();

    if (mMovieStart == 0) {
      mMovieStart = now;
    }

    int dur = mMovie.duration();

    if (dur == 0) {
      dur = DEFAULT_MOVIEW_DURATION;
    }

    mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
  }

  /**
   * Draw current GIF frame
   */
  private void drawMovieFrame(Canvas canvas) {

    mMovie.setTime(mCurrentAnimationTime);

    canvas.save(Canvas.MATRIX_SAVE_FLAG);
    canvas.scale(mScale, mScale);
    mMovie.draw(canvas, mLeft / mScale, mTop / mScale);
    canvas.restore();
  }
  
  @SuppressLint("NewApi")
  @Override
  public void onScreenStateChanged(int screenState) {
    super.onScreenStateChanged(screenState);
    mVisible = screenState == SCREEN_STATE_ON;
    invalidateView();
  }
  
  @SuppressLint("NewApi")
  @Override
  protected void onVisibilityChanged(View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    mVisible = visibility == View.VISIBLE;
    invalidateView();
  }
  
  @Override
  protected void onWindowVisibilityChanged(int visibility) {
    super.onWindowVisibilityChanged(visibility);
    mVisible = visibility == View.VISIBLE;
    invalidateView();
  }
}




Java Source Code List

com.basv.gifmoviewview.MainActivity.java
com.basv.gifmoviewview.widget.GifMovieView.java