接到个需求要播放一个带 Gif 图片的动画,ios 本身就对 Gif 是支持的,android 需要自己实现,因此需要自己自定义一个控件,废话不多,现在贴上代码如下:

/** * 播放 Gif View * Created by William on 2017/7/4. */public class UMGifImageView extends View {    private static final int DEFAULT_VIEW_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 UMGifImageView(Context context) {        this(context, null);    }    public UMGifImageView(Context context, AttributeSet attrs) {        this(context, attrs, R.styleable.CustomTheme_GifViewStyle);    }    public UMGifImageView(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.GifImageView, defStyle,                R.style.Widget_GifMoviewView);        mMovieResourceId = array.getResourceId(R.styleable.GifImageView_gif, -1);        mPaused = array.getBoolean(R.styleable.GifImageView_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.     * 
* {@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_VIEW_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(); }}

然后还要在 attrs.xml 文件中自定义属性:

            

最后,就可以在自己的布局文件中直接使用了:

其中 custom:gif 是直接引用 gif 图片,把 gif 图片放在 drawable 文件夹中即可。

更多相关文章

  1. android apkbuilder.bat批处理
  2. Android(安卓)SDK三种更新失败及其解决方法
  3. Android实现从网络获取图片显示并保存到SD卡的方法
  4. android系统内存管理知识(一)
  5. Android(安卓)在 TextView 中设置超链接、颜色、字体、图片
  6. Android(安卓)Volley之加载网络图片
  7. android 导出带数据库文件的APK
  8. Android之Gradle基础
  9. could not write file\android-7\/system.img, No space left

随机推荐

  1. [RK3399][Android7.1] 调试笔记 --- 设置
  2. Android应用程序获取ROOT权限的方法
  3. Android(安卓)Framework AIDL的使用
  4. 推送sdk (类似百度 推送 ) android mina (
  5. Android(安卓)NDK移植libiconv和libxml2
  6. Eclipse 环境下安装PhoneGap开发插件
  7. android 项目串口通信(serialPort)开发遇到
  8. android 开源 OCR 项目 及手写识别[转]
  9. Android(安卓)Weekly Notes Issue #232
  10. Android新线程中更新主线程UI中的View方