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 自行查阅

通过逐帧动画

首先了解: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源码地址

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

你可能感兴趣的:(Android-五种方式实现gif动画播放)