Android-六种方式实现gif动画播放

大纲

主要想实现的是在一个页面中播放一个动画、就像突然洒金币的效果。
我想要的效果是一个activity覆盖一个activity,并透明。
本文章主要讲如何在动画activity中播放gif动画:(第一种需要把gif转换成一帧一帧的格式,后两种方式是需要把gif--转换成mp4)

  • 通过逐帧动画
    • 内存泄漏、heap size 常识大小 -xms -xmx
  • 通过webview播放
    为了效果更好,应该对webview进行以下处理:
    • webview背景透明
    • webview右下角缩放按钮
    • webview隐藏滚动条
    • 屏幕单机、双击放大、滑动无响应事件
    • 定时销毁动画activity
    • webview屏幕适配
  • 通过videoview播放(将gif--mp4)
    • 自定义videoview 让播放布满整个屏幕
    • videoview隐藏进度条
    • videoview播放本地文件 获取res/raw的绝对地址
  • 通过surfaceview播放(将gif--mp4)
  • 通过glide开源库直接播放gif 自行查阅
  • 对于复杂动画大内存mp4 .gif 推荐使用https://github.com/airbnb/lottie-android
    com.airbnb.android:lottie这个库,让设计师将复杂view通过工具转成json形式,android客户端通过加载json方式加载动画,实现很多复杂动效。
    大杀器Lottie:把AE动画转换成Android原生动画
    这部分工作主要在设计师那里,但这种方式是最轻量切动画效果最好,能很好的播放各种炫酷动画

通过逐帧动画

首先了解:android动画分类
逐帧播放应该是最简单的一种的,就是把连续的图片连起来播放,设置每帧的时间
有两种方式、一种是xml 一种是代码方式实现,
本例我选择代码方式,用一个imageview作为承载,

// 核心代码如下:
    private AnimationDrawable anim;
    private ImageView imageView;
    private void init() {
        LayoutInflater inflater= (LayoutInflater)       
        getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.red_packets_frame_animation_view_layout,this);
        imageView=findViewById(R.id.imageView);
        anim=new AnimationDrawable();

    }
    public void play_animation(){
        for (int i=10;i<=15;i++){
            int id=getResources().getIdentifier("a"+i,"drawable",getContext().getPackageName());
            Drawable drawable=getResources().getDrawable(id);
            anim.addFrame(drawable,100);//100ms
            anim.setOneShot(true);//true 不循环播放
        }
        imageView.setImageDrawable(anim);
        anim.stop();
        anim.start();
    }
  • 但是这种方式真的很容易出oom!如果帧拆分的图片过多,尽量不要使用这种方式,另外补充一点,还有一种Movie类,也像帧播放一样,适用于播放一些小gif,自行了解。

  • 还有提到的oom, 用heap工具可以看到占用内存过多泄漏,在这里简单了解一下常识,

-xms 初始heap size 一般为物理内存的1/64
-xmx 最大heap size 最大为物理内存的1/4

  • JVM内存首先受限于实际的最大物理内存,(运行内存RAM 2\3\4G)
    JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存 小于 40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC 后调整堆的大小.

关于修改堆大小可以看看这篇文章


通过webview播放

在webview播放动画本来是非常简单的一件事,但是如想达到我们想要的效果要修改的地方还是很多的。

  • webview背景透明
  • webview右下角缩放按钮
  • webview隐藏滚动条
  • 屏幕单机、双击放大、滑动无响应事件
  • 定时销毁动画activity (通过开启了一个新的线程,根据动画时间销毁activity)
  • webview屏幕适配
//核心代码
public class AnimationActivity extends Activity  {
    private WebView webView;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation2);
        webView=findViewById(R.id.webview);
        webView.setVerticalScrollBarEnabled(false); //垂直滚动条不显示
        webView.setHorizontalScrollBarEnabled(false);//水平不显示
        WebSettings webSettings=webView.getSettings();
        webSettings.setDisplayZoomControls(false);//隐藏webview缩放按钮
        webSettings.setJavaScriptEnabled(true);
        webSettings.setUseWideViewPort(true);//屏幕适配:设置webview推荐使用的窗口,设置为true
        webSettings.setLoadWithOverviewMode(true);//设置webview加载的页面的模式,也设置为true
        webSettings.setAllowFileAccess(true);
        webSettings.setSupportZoom(true);//是否支持缩放
        webSettings.setBuiltInZoomControls(true);//添加对js功能的支持
        webView.setWebViewClient(new WebViewClient());
        webView.setBackgroundColor(0);
        String gifPath = "file:///android_asset/animation.gif";
        webView.loadUrl(gifPath);
        handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
              switch (msg.what){
                  case 0:
                      webView.destroy();
                      AnimationActivity2.this.finish();
              }
            }
        };
        new Thread(){

            @Override
            public void run() {
                long startTime = System.currentTimeMillis();
                Log.i("test","System.currentTimeMillis()1:"+System.currentTimeMillis());
                try {
                    this.currentThread().sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long endTime = System.currentTimeMillis();
                Log.i("test","System.currentTimeMillis()2:"+System.currentTimeMillis());
                    if (endTime - startTime >4000){
                        //startTime = endTime;
                        Message message=new Message();
                        message.what=0;
                        handler.sendMessage(message);

                    }
            }
        } .start();

    }
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        webView.destroy();
        finish();
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_SCROLL:
                return true;
            case MotionEvent.ACTION_MOVE:
                return true;
            case MotionEvent.ACTION_POINTER_DOWN:
                return true;
            case MotionEvent.ACTION_MASK:
                return true;
            case MotionEvent.ACTION_DOWN:
                return true;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }


}

记得设置activity透明,这样透明的gif的效果就浮现在另一个activity上,效果相对较好。

android:theme="@android:style/Theme.Translucent.NoTitleBar"


通过videoview播放

因为videoview有默认尺寸,而我们想实现全屏动画,需要改变它默认大小 所以要重写相对方法,获得全屏尺寸

    private int screenWidth;
    private int screenHeigh;
//提供一个接口 让activity传入尺寸
    public  void setMetrics(int width,int height){
        screenWidth=width;
        screenHeigh=height;

    }
//重新绘制
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(screenWidth, screenHeigh);
    }
//核心代码如下
public class AnimationActivity3 extends Activity  {
    private GifVideoView gifVideoView;
    private MediaController mc;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation3);
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width=dm.widthPixels;
        int heigh=dm.heightPixels;
        gifVideoView=findViewById(R.id.gifVideoView);
        mc = new MediaController(this);
        mc.setVisibility(View.INVISIBLE);
        gifVideoView.setMetrics(width,heigh);
        gifVideoView.setBackgroundColor(0);
        gifVideoView.setMediaController(mc);
        Uri uri=Uri.parse( "android.resource://"+getPackageName()+"/"+R.raw.test);
        gifVideoView.setVideoURI(uri);
        gifVideoView.start();
        gifVideoView.requestFocus();
        //视频编码格式不支持的情况
        gifVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
                if(what==MediaPlayer.MEDIA_ERROR_SERVER_DIED){
                    Log.v("view exception","Media Error,Server Died"+extra);
                }else if(what==MediaPlayer.MEDIA_ERROR_UNKNOWN){
                    Log.v("video exception","Media Error,Error Unknown "+extra);
                }
                return true;
            }
        });
    }
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finish();
    }
}

小demo效果如图:


Untitled.gif

demo源码地址

留个赞吧鼓励一下。有什么建议或事好的想法可以私聊或评论,我也是初试了解这几种方式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容