Ben Mora
Ben Mora

Reputation: 371

Is it possible to recolor a lottie animation programmatically?

If I have a lottie animation in the form of a json file, is there a way to recolor it in code or even within the json itself?

(To be clear, I hope there's a way to do it without involving After Effects. For instance if I decide to change my app's primary color, the whole app will change except the animation unless there's a way to do that.)

Upvotes: 6

Views: 11203

Answers (3)

android developer
android developer

Reputation: 116010

Here's a Kotlin solution for all cases you might want:

/**sets tint for the animation.
 * @itemsToTint the items elements ("nm" inside "layers") the animation to tint.
 * null will reset all tinting. Empty will set tint for all. */
fun LottieAnimationView.setAnimationTint(itemsToTint: Array<String>?, @ColorInt color: Int) {
    //based on https://stackoverflow.com/a/45607292/878126 https://airbnb.io/lottie/#/android?id=dynamic-properties https://github.com/SolveSoul/lottie-android-colorfilter-sample
    if (itemsToTint == null) {
        //un-tint
        addValueCallback(KeyPath("**"), LottieProperty.COLOR_FILTER) { null }
        return
    }
    addValueCallback(
            KeyPath(*itemsToTint,"**" ),
            LottieProperty.COLOR_FILTER
    ) { PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP) }
}

Upvotes: 3

Patrick Lang
Patrick Lang

Reputation: 751

There is another thread on this topic with the same approach but a bit simplified: How to add a color overlay to an animation in Lottie?

Here's directly an example (Kotlin):

        yourLottieAnimation.addValueCallback(
        KeyPath("whatever_keypath", "**"),
        LottieProperty.COLOR_FILTER
    ) {
        PorterDuffColorFilter(
            Color.CYAN,
            PorterDuff.Mode.SRC_ATOP
        )
    }

You can find the names of the keypaths also in the Lottie editor.

Upvotes: 0

Ben Mora
Ben Mora

Reputation: 371

I figured it out. For this example, let's say I want to recolor a specific layer to Color.RED.

You'll need your LottieAnimationView, a KeyPath, and a LottieValueCallback

private LottieAnimationView lottieAnimationVIew;
private KeyPath mKeyPath;
private LottieValueCallback<Integer> mCallback;

Then in your onCreate (or onViewCreated for a fragment) you'll get the animation with findViewById, as well as "addLottieOnCompositionLoadedListener" to the lottieAnimationView, in which you will setup the "mKeyPath" and "mCallback":

lottieAnimationVIew = findViewById(R.id.animationView);

lottieAnimationView.addLottieOnCompositionLoadedListener(new LottieOnCompositionLoadedListener() {
  @Override
  public void onCompositionLoaded(LottieComposition composition) {
    mKeyPath = getKeyPath(); // This is your own method for getting the KeyPath you desire. More on that below.
    mCallback = new LottieValueCallback<>();
    mCallback.setValue(Color.RED);
    checkBox.addValueCallback(mKeyPath, LottieProperty.COLOR, mCallback);
  }
});

The argument "LottieProperty.COLOR" specifies which property I am changing.

There's probably a better way to do this, but here's my "getKeyPath" method for finding the specific thing I want to change. It will log every KeyPath so you can see which one you want. Then it returns it once you've supplied the correct index. I saw that the one I want is the 5th in the list, hence the hard-coded index of 4.

private KeyPath getKeyPath() {
  List<KeyPath> keyPaths = lottieAnimationView.resolveKeyPath(new KeyPath("Fill", "Ellipse 1", "Fill 1"));
        
  for (int i = 0; i < keyPaths.size(); i++) {
    Log.i("KeyPath", keyPaths.get(i).toString());
  }
        
  if (keyPaths.size() == 5) {
    return keyPaths.get(4);
  }
  else {
    return null;
  }
}

Note that the "Fill", "Ellipse 1", "Fill 1" are strings I supplied to narrow the list down to just the ones that have those keys, because I know that the layer I want will be among those. There's likely a better way to do this as well.

Upvotes: 5

Related Questions