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.)
3 Answers
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.
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 if (itemsToTint == null) { //un-tint addValueCallback(KeyPath("**"), LottieProperty.COLOR_FILTER) { null } return } addValueCallback( KeyPath(*itemsToTint,"**" ), LottieProperty.COLOR_FILTER ) { PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP) }
} 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.