iOS中如何通过代码修改Lottie输入指示器动画的颜色?
Hey there! I see you're trying to change the color of your typing indicator's dots using Lottie without editing the original JSON file, but your current code isn't working. Let's break down why that's happening and fix it step by step.
Why Your Current Code Isn't Working
There are two common culprits here:
- Timing issue: You're trying to set the color before the animation has finished loading. Lottie can't modify properties that haven't been initialized yet.
- Incorrect keypath: The
"boule.Ellipse 1.Fill 1.Color"path might not match the actual layer hierarchy in your JSON animation. Guessing keypaths often leads to misses.
Step 1: Verify the Correct Keypath
First, let's print out the animation's layer hierarchy to get the exact keypath for the fill color. Add this code right after your animation loads:
animationView.load(completion: { [weak self] success in guard success, let self = self else { return } // Print the full hierarchy to find your target property self.animationView.logHierarchy() })
You'll see output in your console that looks something like this:
Animation hierarchy: Root (Layer) ├─ boule (Shape Layer) │ ├─ Ellipse 1 (Shape) │ │ ├─ Fill 1 (Fill) │ │ │ └─ Color (Color) │ ├─ Ellipse 2 (Shape) │ │ ├─ Fill 1 (Fill) │ │ │ └─ Color (Color)
Use the exact path from this log (e.g., "boule.Ellipse 1.Fill 1.Color" if it matches, or adjust if your layers have different names).
Step 2: Use Lottie's Recommended API for Dynamic Color Changes
Lottie's newer LOTValueCallback API is more reliable than the old setValue:forKeyPath:atFrame: method, especially for dynamic property changes. Here's how to implement it correctly:
private let animationView = LOTAnimationView(name: Constants.ImageAssets.typingIndicatorIcon, bundle: Bundle(identifier: Constants.GenericKeys.bundleIdentifier)!) private func loadTypingIndicator() { animationView.loopAnimation = true animationView.translatesAutoresizingMaskIntoConstraints = true // Note: Using false with AutoLayout is usually better, but keeping your original setting here // Wait for the animation to load completely before modifying properties animationView.load(completion: { [weak self] success in guard success, let self = self else { return } // 1. Define the keypath for the fill color (use the path from logHierarchy!) let colorKeypath = LOTKeypath(keypath: "boule.Ellipse 1.Fill 1.Color") // 2. Create a color callback to set your desired color let greenColorCallback = LOTColorValueCallback(color: UIColor.green.cgColor) // 3. Assign the callback to the animation view self.animationView.setValueCallback(greenColorCallback, for: colorKeypath) // If you have multiple dots, repeat for each ellipse or use a wildcard: // let multiDotKeypath = LOTKeypath(keypath: "boule.*.Fill 1.Color") // self.animationView.setValueCallback(greenColorCallback, for: multiDotKeypath) // Start the animation after setting up the color self.animationView.play() }) }
Step 3: (Optional) Fix the Old API If You Prefer It
If you really want to stick with setValue:forKeyPath:atFrame:, just move it inside the load completion block to ensure the animation is loaded first:
animationView.load(completion: { [weak self] success in guard success, let self = self else { return } self.animationView.setValue(UIColor.green, forKeyPath: "boule.Ellipse 1.Fill 1.Color", atFrame: 0) self.animationView.play() })
Key Takeaways
- Always wait for the animation to finish loading before modifying any properties.
- Use
logHierarchy()to get the exact keypath instead of guessing. - The
LOTValueCallbackAPI is the modern, reliable way to dynamically change Lottie animation properties.
内容的提问来源于stack exchange,提问作者Devan

