欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SVGA JAVA库在源码AOSP Android.mk中引用及应用

程序员文章站 2022-05-04 07:49:22
...

SVGA JAVA库在源码AOSP Android.mk中引用及应用

SVGA 纯Java库做成

我用Android studio kotlin插件自带的转化工具,这个百度都有就不说了。不过不能百分百转化,有些问题就要自己手动改了。还要有些系统不支持的也要换,比如lambda表达式Java7不支持,就改掉了。依赖的kotlin库也要换成Java的。
然后我把SVGA在mk中配置成静态jar包:svga

SVGA库引用

在Android.mk中配置:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src) 

LOCAL_PACKAGE_NAME := svgademo

LOCAL_PRIVILEGED_MODULE := true

LOCAL_DEX_PREOPT:=false

LOCAL_CERTIFICATE := platform

LOCAL_MODULE_TAGS := optional

LOCAL_PROGUARD_ENABLED := disabled
LOCAL_PROGUARD_FLAG_FILES := proguard-rules.pro

LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
    frameworks/support/v7/appcompat/res \
    vendor/nextev/frameworks/support/3rdparty/svga/res

LOCAL_ASSET_DIR :=  $(LOCAL_PATH)/assets

LOCAL_STATIC_JAVA_LIBRARIES += \
    svga \

LOCAL_AAPT_FLAGS := --auto-add-overlay \
                --extra-packages android.support.v7.appcompat \
                --extra-packages com.opensource.svgaplayer \
                

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))


SVGA使用

layout XML配置

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SimpleActivity">

    <com.opensource.svgaplayer.SVGAImageView
        android:id="@+id/svgaImage"
        android:layout_width="match_parent"
        android:layout_height="658dp"
        android:layout_alignParentTop="true"
        app:autoPlay="true"
        app:loopCount="1"
        app:clearsAfterStop = "false"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">
        
       ...
       我的Button控件
       ...
       
    </LinearLayout>

</RelativeLayout>

在 XML 中,允许定义以下这些标签:

用于表示 svga 文件的路径,提供一个在 assets 目录下的文件名,或者提供一个 http url 地址。

source: String

默认为 true,当动画加载完成后,自动播放。

autoPlay: Boolean

默认为 0,设置动画的循环次数,0 表示无限循环。

loopCount: Int

默认为 true,当动画播放完成后,是否清空画布。

clearsAfterStop: Boolean

默认为 true,当 SVGAImageView 触发 onDetachedFromWindow 方法时,是否清空画布。

clearsAfterStop: Boolean

默认为 Forward,可以是 Forward、 Backward。

fillMode: Forward/Backward
Forward 表示动画结束后,将停留在最后一帧。
Backward 表示动画结束后,将停留在第一帧。

资源文件

把.svga文件放到assets文件下,Android.mk中LOCAL_ASSET_DIR配置好路径。

ActivityMain

package com.tecinno.svgaplayer;

import android.app.Activity;
import android.net.http.HttpResponseCache;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.IOException;
import com.opensource.svgaplayer.SVGAImageView;

public class SimpleActivity extends Activity {

    private Button button1, button2, button3, button4;
    private SVGAImageView svgaImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);
        //播放网络动画时需要配置的缓存
        try {
            File cacheDir  = new  File(getApplicationContext().getCacheDir(),"http");
            HttpResponseCache.install(cacheDir, 1024 * 1024 * 128);
        } catch (IOException e) {
            e.printStackTrace();
        }
        initView();
    }

    private void initView(){
        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);
        button4 = findViewById(R.id.button4);
        svgaImage = findViewById(R.id.svgaImage);

        final SvgaUtils svgaUtils = new SvgaUtils(SimpleActivity.this, svgaImage);
        //startAnimator前需要先initAnimator,完成一些监听注册
        svgaUtils.initAnimator();

        //button监听
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                svgaUtils.startAnimator("alarm", true);
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                svgaUtils.startAnimator("angel", false);
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                svgaUtils.startAnimator("posche", false);
            }
        });
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                svgaUtils.startAnimator("rose_1.5.0", false);
            }
        });
    }
}

SVGAUtils

showSVGAStep()可以监听手指左右滑动来正反播放动画。

package com.tecinno.svgaplayer;

import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.opensource.svgaplayer.SVGACallback;
import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGADynamicEntity;
import com.opensource.svgaplayer.SVGAImageView;
import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGARange;
import com.opensource.svgaplayer.SVGAVideoEntity;
import java.net.URL;

/**
 * author: jieqin.liu
 * date: on 2021/02/23.
 * describe:SVGA工具类
 * 使用时首先调用初始化数据方法,
 * 然后再调用开始动画的方法
 */

public class SvgaUtils {
    private Context context;
    private SVGAImageView svgaImage;
    private SVGAParser parser;
    private final static String TAG = "SvgaUtils";
    private String needLoop;
    private SVGARange ran;
    private FrameEntry frameEntry;

    public SvgaUtils(Context context, SVGAImageView svgaImage) {
        this.context = context;
        this.svgaImage = svgaImage;
        //播放的帧顺序,第一个参数是开始位置,第二个参数是帧数
        ran = new SVGARange(9,20);
    }

    /**
     * 初始化数据
     */
    public void initAnimator() {
        //左右滑动播放动画的灵敏度
        final int slideSpeed = 10;
        parser = new SVGAParser(context);
        //监听大动画的控件周期
        svgaImage.setCallback(new SVGACallback() {
            @Override
            public void onPause() {
                Log.e(TAG, "onPause");
            }

            @Override
            public void onFinished() {
                Log.e(TAG, "onFinished"+ (needLoop.equals("yes")? ", loop play":" "));
                if(needLoop.equals("no")){
                    stopSVGA();
                } else {
                	//从第几帧开始播放,正序播放
                    svgaImage.stepToFrame(0, false);

                    //以给定的顺序播放,倒序播放
//                    svgaImage.startAnimation(ran,true);

                    //以给定的顺序播放,正序播放
//                    svgaImage.startAnimation(ran,false);
                }
            }

            @Override
            public void onRepeat() {
                Log.e(TAG, "onRepeat");
                stopSVGA();
            }

            @Override
            public void onStep(int i, double v) {
                Log.e(TAG, "onStep i :"+i+", maxFrame : " + frameEntry.maxFrame);
                //保存当前是第几帧
                frameEntry.currentFrame = i;
            }
        });
        //滑动监听
        svgaImage.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                switch (event.getAction()) {
                    // 按下
                    case MotionEvent.ACTION_DOWN:
                        Log.e(TAG,"ACTION_DOWN X "+ event.getX()+ " Y "+event.getY());
                        break;
                    // 移动
                    case MotionEvent.ACTION_MOVE:
                        Log.e(TAG,"ACTION_MOVE X "+ event.getX()+ " Y "+event.getY());
                        float currentPosX = event.getX();
                        if(currentPosX - frameEntry.mPosX > slideSpeed){
                            frameEntry.mPosX = currentPosX;
                            showSVGAStep(false);
                        } else if(frameEntry.mPosX - currentPosX > slideSpeed){
                            frameEntry.mPosX = currentPosX;
                            showSVGAStep(true);
                        }
                        break;
                    // 拿起
                    case MotionEvent.ACTION_UP:
                        Log.e(TAG,"ACTION_UP X "+ event.getX()+ " Y "+event.getY());
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }

    /**
     * 显示动画
     */
    public void startAnimator(String svgaName, boolean isLoop) {
        Log.e(TAG,"startAnimator");
        if (svgaName != null) {
            needLoop = isLoop ? "yes" : "no";
            //播放本地动画
            showSVGA(svgaName);
            //播放网络动画
//            showNetSVGA("https://github.com/yyued/SVGA-Samples/blob/master/posche.svga?raw=true");
            //播放网络动画并插入图片
//            showdynamicSVGA("https://github.com/yyued/SVGA-Samples/blob/master/kingset.svga?raw=true");

        } else {
            Log.e(TAG,"startAnimator svgaName is null");
            return;
        }
    }

    /**
     * 停止动画
     */
    private void stopSVGA() {
        if (svgaImage.isAnimating()) {
            svgaImage.stopAnimation();
        }
    }
    /**
     * 滑动播放动画,向右滑动顺序播放,向左滑动倒序播放
     * reserse:播放顺序,顺序播放或者倒放
     */
    public void showSVGAStep(boolean reverse){
        if(svgaImage == null && frameEntry == null){
            Log.e(TAG, svgaImage == null ? "svgaImage is null" : "frameEntry is null");
            return;
        }
        int nextFrame;
        SVGARange range;
        if(reverse){ //倒序播放
            //下一帧
            nextFrame = frameEntry.currentFrame - 1;
            //配置播放的帧和帧数
            range = new SVGARange(nextFrame < 0 ? frameEntry.maxFrame : nextFrame,1);
        } else{//顺序播放
            //下一帧
            nextFrame = frameEntry.currentFrame + 1;
            //配置播放的帧和帧数
            range = new SVGARange(nextFrame >= frameEntry.maxFrame ? 0:nextFrame, 1);
        }
        //开始播放
        svgaImage.startAnimation(range, reverse);
    }
    /**
     * 播放动画
     */
    private void showSVGA(String svagName) {
        try {
            parser.parse(svagName+".svga", new SVGAParser.ParseCompletion() {
                @Override
                public void onComplete(SVGAVideoEntity svgaVideoEntity) {
                    //保存当前动画最大帧数,方便后面随机播放
                    frameEntry = new FrameEntry(svgaVideoEntity.getFrames());
                    //解析动画成功,到这里才真正的显示动画
                    SVGADrawable drawable = new SVGADrawable(svgaVideoEntity);
                    svgaImage.setImageDrawable(drawable);
                    svgaImage.startAnimation();
                }
                @Override
                public void onError() {
                    //停止播放
                    stopSVGA();
                }
            });
        } catch (Exception e) {
            Log.e(TAG,"show svga error : "+e);
        }
    }

    /**
     * 播放网络动画
     */
    private void showNetSVGA(String svagURL) {
        try {
            parser.parse(new URL(svagURL), new SVGAParser.ParseCompletion() {
                @Override
                public void onComplete(SVGAVideoEntity svgaVideoEntity) {
                    //保存当前动画最大帧数,方便后面随机播放
                    frameEntry = new FrameEntry(svgaVideoEntity.getFrames());
                    //解析动画成功,到这里才真正的显示动画
                    svgaImage.setVideoItem(svgaVideoEntity);
                    svgaImage.startAnimation();
                }
                @Override
                public void onError() {
                    //停止播放
                    stopSVGA();
                }
            });
        } catch (Exception e) {
            Log.e(TAG,"show svga error : "+e);
        }
    }
    /**
     * 播放动态动画,动画中插入自定义图片
     */
    private void showdynamicSVGA(String svagURL) {
        try {
            parser.parse(new URL(svagURL), new SVGAParser.ParseCompletion() {
                @Override
                public void onComplete(SVGAVideoEntity svgaVideoEntity) {
                    //保存当前动画最大帧数,方便后面随机播放
                    frameEntry = new FrameEntry(svgaVideoEntity.getFrames());
                    //解析动画成功,到这里才真正的显示动画
                    SVGADynamicEntity dynamicEntity = new SVGADynamicEntity();
                    dynamicEntity.setDynamicImage("https://github.com/PonyCui/resources/blob/master/svga_replace_avatar.png?raw=true", "99"); // Here is the KEY implementation.
                    SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity);
                    svgaImage.setImageDrawable(drawable);
                    svgaImage.startAnimation();
                }
                @Override
                public void onError() {
                    //停止播放
                    stopSVGA();
                }
            });
        } catch (Exception e) {
            Log.e(TAG,"show svga error : "+e);
        }
    }
    /*
    * 随机播放动画时保存的动画和touch位置信息,需要在parser完成时初始化。
    *
    * mPosX:当前touch X轴位置
    * currentFrame:当前播放的是第几帧
    * maxFrame:该动画有多少帧
    *
    * */
    public class FrameEntry{
        //当前触点X轴位置
        public float mPosX;
        //当前播放是第几帧
        public int currentFrame;
        //最大帧数
        public int maxFrame;

        public FrameEntry(int maxFrame){
            mPosX = 0;
            currentFrame = 0;
            this.maxFrame = maxFrame;
        }
    }

}