1. 程式人生 > >Android的Gif動畫載入

Android的Gif動畫載入

我們都知道Android是不直接支援Gif檔案的載入的(當然了現在的Glide圖片載入框架是支援GIF格式的檔案的,Picasso暫時是不支援的,但是為了這一個小小的功能卻匯入一個庫豈不是得不償失,另外我們這裡主要是學習),但是有時候美工會直接給我們Gif格式的檔案,這時候如果能夠直接使用的話豈不是比使用逐幀動畫方便一些(先不考慮效能的問題),那麼我們就會想辦法,下面是一個自定義的GifView

<declare-styleable name="GifView">
        <attr name="gif" format="reference"/>
        <attr name="paused" format="boolean"/>
    </declare-styleable>
    <declare-styleable name="CustomTheme">
        <attr name="gifViewStyle" format="reference"/>
    </declare-styleable>
public class GifView extends View {
    /**
     * 預設為1秒
     */
    private static final int DEFAULT_MOVIE_DURATION = 1000;
    private int mMovieResourceId;
    private Movie mMovie;
    private long mMovieStart;
    private int mCurrentAnimationTime = 0;
    private float mLeft;
    private float mTop;
    private float mScale;
    private int mMeasuredMovieWidth;
    private int mMeasuredMovieHeight;
    private boolean mVisible = true;
    private volatile boolean mPaused = false;

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

    public GifView(Context context, AttributeSet attrs) {
        this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
    }

    public GifView(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) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        // 從描述檔案中讀出gif的值,創建出Movie例項
        final TypedArray array = context.obtainStyledAttributes(attrs,
                R.styleable.GifView, defStyle, R.style.AppTheme);
        mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
        mPaused = array.getBoolean(R.styleable.GifView_paused, false);
        array.recycle();
        if (mMovieResourceId != -1) {
            mMovie = Movie.decodeStream(getResources().openRawResource(
                    mMovieResourceId));
        }
    }

    /**
     * 設定gif圖資源
     *
     * @param movieResId
     */
    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();
    }

    /**
     * 設定暫停
     *
     * @param paused
     */
    public void setPaused(boolean paused) {
        this.mPaused = paused;
        if (!paused) {
            mMovieStart = android.os.SystemClock.uptimeMillis()
                    - mCurrentAnimationTime;
        }
        invalidate();
    }

    /**
     * 判斷gif圖是否停止了
     *
     * @return
     */
    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();
            int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
            float scaleW = (float) movieWidth / (float) maximumWidth;
            mScale = 1f / scaleW;
            mMeasuredMovieWidth = maximumWidth;
            mMeasuredMovieHeight = (int) (movieHeight * mScale);
            setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
        } else {
            setMeasuredDimension(getSuggestedMinimumWidth(),
                    getSuggestedMinimumHeight());
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        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);
            }
        }
    }

    @SuppressLint("NewApi")
    private void invalidateView() {
        if (mVisible) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                postInvalidateOnAnimation();
            } else {
                invalidate();
            }
        }
    }

    private void updateAnimationTime() {
        long now = android.os.SystemClock.uptimeMillis();
        // 如果第一幀,記錄起始時間
        if (mMovieStart == 0) {
            mMovieStart = now;
        }
        // 取出動畫的時長
        int dur = mMovie.duration();
        if (dur == 0) {
            dur = DEFAULT_MOVIE_DURATION;
        }
        // 算出需要顯示第幾幀
        mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
    }

    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();
    }
}
使用的時候就像ImageView一樣,這裡的iv就是gif檔案,不過是在raw檔案下
        //設定gif動畫
        mGifView = (GifView) findViewById(R.id.mygifview);
        mGifView.setMovieResource(R.raw.iv);


相關推薦

做一個可複用的 echarts-vue 元件(延遲動畫載入

在 vue 專案使用 echarts 的場景中,以下三點不容忽視:1. 視覺化的資料往往是非同步載入的;2. 若一個頁面存在大量的圖表( 尤其當存在關係圖和地圖時 ),往往會導致該頁面的渲染速度很慢並可能在幾秒內卡死,產生極差的使用者體驗。3. 引入 echarts 元件導致編譯後的檔案過大從而使得首次訪

一個很low的 動畫載入效果(keyframes )

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鳥教程(runoob.com)</title> <style> div { max-w

flask加vue 動畫 載入更多

曾經使用flask_paginate(地址:https://blog.csdn.net/qq_42239520/article/details/80378095)進行分頁,現在又想新的想法,怎麼才能和其它大多數主流網站一樣,通過點選載入更多,獲取到更多的頁面呢?   原始碼地址:h

Android DrawableAnimation逐幀動畫載入多圖(OOM的解決)

想做一個逐幀動畫,用了一百來張圖片,結果記憶體溢位了,找了半天最後算是解決了。 本來是在drawable裡面寫一個animation-list,設定ImageView的backgroud, 然後在Activity裡面animationDrawable = (Animatio

動畫載入大量圖片OOM的解決辦法

這是在別人程式碼基礎上更改的。 程式碼如下: public class SceneAnimation { /** * target imageView */ private ImageView mImageView;

Android的Gif動畫載入

我們都知道Android是不直接支援Gif檔案的載入的(當然了現在的Glide圖片載入框架是支援GIF格式的檔案的,Picasso暫時是不支援的,但是為了這一個小小的功能卻匯入一個庫豈不是得不償失,另外我們這裡主要是學習),但是有時候美工會直接給我們Gif格式的檔案,這時候

Android逐幀動畫,逐幀動畫載入圖片過多時OOM異常的解決和替代方法

1.首先新增逐幀動畫 播放逐幀動畫,在工程中res目錄下建立一個anim資料夾,新增動畫anim_welcome.xml檔案如下: <?xml version="1.0" encoding="utf-8"?> <animation-li

FBX動畫載入功能 程式實現(一)

FBX  動畫資料結構 解釋 FbxScene     一個場景包含一個或者跟多的動畫棧。如過在場景中沒有動畫,那麼你將不需要用到動畫棧或者其他動畫類成員 FbxAnimStack    動畫棧是用來包含一個或者多個動畫圖層的最高等級的容器 FbxAnimLayer

cocos2d-x 動畫載入 延時執行

void SnatchDeveloper::hechengframeCacheAction() {          CCArray * hechengFrames=CCArray::create();     for (int i=0; i<8; i++)    

【跟我一起學Unity3D】代碼中分割圖片而且載入幀序列動畫

stream textfield 控制 調整 我們 pos apply fonts 一個 在Cocos2dx中。對大圖的處理已經封裝好了一套自己的API,可是在Unity3D中貌似沒有類似的API(好吧,實際上是有的,並且功能更強大),或

CSharpGL(50)使用Assimp載入骨骼動畫

CSharpGL(50)使用Assimp載入骨骼動畫 在(http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html)介紹了C++用Asismp庫載入骨骼動畫的原理和流程。 在(http://wiki.jikexueyuan.com/project

flutter動畫和進行圖片的載入

1.進行簡單的移動,旋轉等動畫操作,具體的操作可以檢視api transform: new Matrix4.rotationZ(0.1), 沿z軸旋轉 transform: new Matrix4.translationValues(10.0, 30.0, 30.0), 2.對於Contai

網頁頁面預載入動畫的實現,載入後隱藏

我們做web app的時候,可以做一個頁面載入廣告,在你網頁載入的時候,先出現一段gif動圖或者是海報。 下面是實現頁面載入動畫的程式碼 首先js程式碼的實現 (function($){ $(window).load(function(){ $('#b

android 動畫--幀動畫--仿美團載入中小人

1 把資源圖片放到drawable中 2 在drawable中寫動畫的xml檔案animation01 Animation01.xml <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:a

Android正在載入動畫

LoadingImage 正在載入的ImageView 使用方法 maven <dependency> <groupId>com.hlq</groupId> <artifactId>loading

安卓-Loading載入動畫

前段時間用到了loading載入動畫,這裡記錄兩種方法。一種是多個影象變化組成的動畫,一種圖片本身的動作,以轉圈為例下面是程式碼。 這是效果圖 原始碼下載地址 Loading載入中動畫專案原始碼下載 第一種多個圖片變化 在res的anim資料夾中新建一個loadingf

CSS3載入等待動畫(loading)

效果: CSS樣式表程式碼: #errmsg { color: #ff0000; text-align: center; margin: 0px auto; line-height: 30px; } #colorfulPulse { width

ajax 非同步載入載入動畫

1.當資料恢復後臺程式碼處理量較大時,希望前臺能夠有個提示或者動畫,讓使用者知道後臺在運轉,讓使用者體驗好點 $.ajax({ url: '${ctx}/admin/course/sysAllContainerToCourse.json', data: param, type:

OkHttp網路載入資料+RecyclerView展示+屬性動畫

MainActivity.java public class MainActivity extends AppCompatActivity implements HttpUrls.ff{ private ImageView mImageView; private Rec

為頁內的tab新增的iframe新增載入動畫過渡效果

var iframe = $("iframe[data-id=" + id + " ]"); if (iframe.length > 0) { var exist = $(iframe[0]).attr("exist");