Lottie 动画库使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Hana_one/article/details/81916641

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

猜你喜欢

转载自blog.csdn.net/Hana_one/article/details/81916641
今日推荐