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

Lottie 动画库使用

程序员文章站 2024-03-26 11:46:23
...

Lottie

基本使用

  • xmls常用属性
app:lottie_autoPlay="false"   //自动播放 相当于 playAnimation()
app:lottie_fileName="lottiefiles.com - ATM.json"//设置动画文件 相当于setAnimation("xx.json") 
app:lottie_loop="true" // loop(true)
app:lottie_progress="1.0f"//setProgerss(1.0f)
app:lottie_scale="0.5"//setScale(0.5f)
app:lottie_cacheStrategy="strong"
  • 常用Api

animationView.loop(true);
animationView.setProgress(1.0f);
animationView.setScale(1f);
animationView.playAnimation();
animationView.isAnimating()
animationView.pauseAnimation();
animationView.cancelAnimation();
...

//设置动画的方式
setAnimation(String);
setAnimation(JSONObject)
setComposition(LottieComposition)
setAnimation(String animationName,  CacheStrategy cacheStrategy) 

//控制动画播放
playAnimation(int startFrame,int endFrame)
playAnimation(float startProgress, float endProgress)
如果在json文件中引用了图片资源,就需通过setImageAssetsFolder(“airbnb_loader/”)的方法设置其所在assets文件夹下的位置,否者会报错。
playAnimation(startFrame, endFrame)
playAnimation(startProgress, endProgress)

上面两个方法用来播放指定的帧区间内或者进度区间的动画,在Api内部playAnimation(startFrame, endFrame) 实际通过调用的是playAnimation(startProgress, endProgress),

 public void playAnimation(final int startFrame, final int endFrame) {
   ...
    playAnimation(startFrame / composition.getDurationFrames(),
        endFrame / composition.getDurationFrames());
  }
  • 加载动画资源的方式
LottieComposition.Factory.fromAssetFileName(Context context, String fileName,OnCompositionLoadedListener loadedListener);
LottieComposition.Factory.fromInputStream(Context context, InputStream stream, OnCompositionLoadedListener loadedListener);
LottieComposition.Factory.fromJson(Resources res, JSONObject json, OnCompositionLoadedListener loadedListener);

除了简单粗暴的animationView.setAnimation(“lottiefiles.com - ATM.json”)方式去设置动画的json 文件还可以通过上面三种方式去加载,并在回调中设置动画。

  public void setAnimation(final String animationName, final CacheStrategy cacheStrategy) {
       ...
        compositionLoader = LottieComposition.Factory.fromAssetFileName(getContext(), animationName,
                new OnCompositionLoadedListener() {
                    @Override
                    public void onCompositionLoaded(LottieComposition composition) {
                        if (cacheStrategy == CacheStrategy.Strong) {
                            STRONG_REF_CACHE.put(animationName, composition);
                        } else if (cacheStrategy == CacheStrategy.Weak) {
                            WEAK_REF_CACHE.put(animationName, new WeakReference<>(composition));
                        }

                        setComposition(composition);
                    }
                });
    }

可以看到在setAnimation(xx.josn)方法内部调用的是

LottieComposition.Factory.fromAssetFilName(Context context, String fileName,OnCompositionLoadedListener loadedListener),  

在load 完成后直接通过 setComposition(composition)进行设置。

在LottieComposition.Factory.fromAssetFilName(Context context, String fileName,OnCompositionLoadedListener loadedListener) 内部又调用了fromAssetFileName,这..
 public static Cancellable fromAssetFileName(Context context, String fileName,
                                                    OnCompositionLoadedListener loadedListener) {
            InputStream stream;
            try {
                stream = context.getAssets().open(fileName);
            } catch (IOException e) {
                throw new IllegalStateException("Unable to find file " + fileName, e);
            }
            return fromInputStream(context, stream, loadedListener);
        }

对于LottieComposition.Factory.fromJson(Resources res, JSONObject json, OnCompositionLoadedListener loadedListener) 方法 可以用来从网上加载出动画文件,在通过该方法进行load, 也可以通过setAnimation(JSONObject)方法直接进行设置,其内部调用了LottieComposition.Factory.fromJson方法

  public void setAnimation(final JSONObject json) {
    cancelLoaderTask();
    compositionLoader = LottieComposition.Factory.fromJson(getResources(), json, loadedListener);
  }
缓存策略(strong weak none三种)
  • 如果要重复使用某个动画的话,可以为其设置缓存策略,你可以通过
java 代码
setAnimation(String animationName,  CacheStrategy cacheStrategy) 
xml 中设置
app:lottie_cacheStrategy="strong"

在setAnimal(String) 方法

 public void setAnimation(String animationName) {
        setAnimation(animationName, defaultCacheStrategy);
    }

//不同缓存策略的方式

//两个map数组分别存放不同缓存策略的对象
 private static final Map<String, LottieComposition> STRONG_REF_CACHE = new HashMap<>();
private static final Map<String, WeakReference<LottieComposition>> WEAK_REF_CACHE = new HashMap<>();

 if (cacheStrategy == CacheStrategy.Strong) {
     STRONG_REF_CACHE.put(animationName, composition);
    } else if (cacheStrategy == CacheStrategy.Weak) {
    WEAK_REF_CACHE.put(animationName, new WeakReference<>(composition));
    }

其中默认的缓存为weak.

LottieAnimationView的监听
animationView.addAnimatorListener(Animator.AnimatorListener listener);
animationView.addAnimatorUpdateListener(ValueAnimator.AnimatorUpdateListener updateListener);

Lottie实现的基本过程

json文件 ——> LottieComposition ——> LottieDrawable ——> LottieAnimationView
  "v": "4.10.1",      bodymovin的版本//版本要求在4.5.0(包含4.5.0)以上
  "fr": 25,         帧率
  "ip": 0,          起始关键帧
  "op": 350,        结束关键帧
  "w": 1080,        图片宽度
  "h": 1080,        图片高度
  "nm": "day1",     图片名称
  "assets": [],     图片集合
  "layers":         图层集合
  • LottieCopposition 相当于一个model类,其中包含着所有的数据信息

  • 在上面的几种设置动画的方式中,在其内部,通过FileCompositionLoader 把json文件数据信息加载到LottieComposition中

      FileCompositionLoader loader =
                    new FileCompositionLoader(context.getResources(), loadedListener);
            loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, stream);

具体加载json的方法

  static LottieComposition fromJsonSync(Resources res, JSONObject json) {
      Rect bounds = null;
      float scale = res.getDisplayMetrics().density;
      int width = json.optInt("w", -1);
      int height = json.optInt("h", -1);

      if (width != -1 && height != -1) {
        int scaledWidth = (int) (width * scale);
        int scaledHeight = (int) (height * scale);
        bounds = new Rect(0, 0, scaledWidth, scaledHeight);
      }

      long startFrame = json.optLong("ip", 0);
      long endFrame = json.optLong("op", 0);
      float frameRate = (float) json.optDouble("fr", 0);
      String version = json.optString("v");
      String[] versions = version.split("[.]");
      int major = Integer.parseInt(versions[0]);
      int minor = Integer.parseInt(versions[1]);
      int patch = Integer.parseInt(versions[2]);
      LottieComposition composition = new LottieComposition(
          bounds, startFrame, endFrame, frameRate, scale, major, minor, patch);
      JSONArray assetsJson = json.optJSONArray("assets");
      parseImages(assetsJson, composition);
      parsePrecomps(assetsJson, composition);
      parseFonts(json.optJSONObject("fonts"), composition);
      parseChars(json.optJSONArray("chars"), composition);
      parseLayers(json, composition);
      return composition;
    }

LottieComposition类中还提供了一下几种静态方法来解析json文件

LottieComposition 中的静态方法来解析json文件

parseLayers(JSONObject json, LottieComposition composition)
parsePrecomps( @Nullable JSONArray assetsJson, LottieComposition composition)
parseImages(@Nullable JSONArray assetsJson, LottieComposition composition)
parseFonts(@Nullable JSONObject fonts, LottieCompositioncomposition)
parseChars(@Nullable JSONArray charsJson, LottieComposition composition)
addLayer(List<Layer> layers, LongSparseArray<Layer> layerMap, Layer layer)
  • LottieDrawable 是Lottiecomposition数据的载体,以上的几种对LottieAnimationView设置数据的方式,都会调用LottieDrawable的 setComposition(LottieComposition composition) 方法
  public void setComposition(@NonNull LottieComposition composition) {
    if (L.DBG) {
      Log.v(TAG, "Set Composition \n" + composition);
    }
    lottieDrawable.setCallback(this);
    //下面方法判断是不是已经存在的信息
    boolean isNewComposition = lottieDrawable.setComposition(composition);
    enableOrDisableHardwareLayer();
    if (!isNewComposition) {
      // We can avoid re-setting the drawable, and invalidating the view, since the composition
      // hasn't changed.
      return;
    }
    //view的适配
    int screenWidth = Utils.getScreenWidth(getContext());
    int screenHeight = Utils.getScreenHeight(getContext());
    int compWidth = composition.getBounds().width();
    int compHeight = composition.getBounds().height();
    if (compWidth > screenWidth ||
        compHeight > screenHeight) {
      float xScale = screenWidth / (float) compWidth;
      float yScale = screenHeight / (float) compHeight;

      float maxScaleForScreen = Math.min(xScale, yScale);
      setScale(Math.min(maxScaleForScreen, lottieDrawable.getScale()));

    // If you set a different composition on the view, the bounds will not update unless
    // the drawable is different than the original.
    setImageDrawable(null);
    setImageDrawable(lottieDrawable);

    this.composition = composition;

    requestLayout();
  }
Lottie中做了状态的保存,保存了动画的一些属性,状态,以及进度等等。在屏幕旋转以及其他场景,需要保存状态的时候,不用我们自己保存。
  @Override protected Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState ss = new SavedState(superState);
    ss.animationName = animationName;
    ss.progress = lottieDrawable.getProgress();
    ss.isAnimating = lottieDrawable.isAnimating();
    ss.isLooping = lottieDrawable.isLooping();
    ss.imageAssetsFolder = lottieDrawable.getImageAssetsFolder();
    return ss;
  }

  @Override protected void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
      super.onRestoreInstanceState(state);
      return;
    }

    SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());
    this.animationName = ss.animationName;
    if (!TextUtils.isEmpty(animationName)) {
      setAnimation(animationName);
    }
    setProgress(ss.progress);
    loop(ss.isLooping);
    if (ss.isAnimating) {
      playAnimation();
    }
    lottieDrawable.setImagesAssetsFolder(ss.imageAssetsFolder);
  }
库的使用相对简单,能实现复杂的效果,可以很灵活的去设置动画的,无论从网络或者本地获取,同时支持绝大多数AE效果,能够满足正常的需求,亲测好用 ,值得推荐。
详情见官方文档:airbnb.io/lottie
相关标签: androdi