为何自定义Shakeable协议的shake动画不生效但print语句正常执行?
Hey there! Let's break down why your shake animation isn't showing up even though the print("Shaked!") line is working. Since the print statement fires, we know your shake() method is definitely being called—so the problem lies in how the animation is set up or applied, not the method itself. Here are the most common fixes for this issue, tailored for new developers:
1. Did you forget to add the animation to the view's layer?
This is the #1 mistake new folks make with Core Animation. You can create the CABasicAnimation object all day, but if you don't add it to the view's layer, it will never run. Double-check your UIView extension code to make sure you have this critical line:
extension UIView: Shakeable { func shake() { // Create your shake animation let shakeAnim = CABasicAnimation(keyPath: "transform.translation.x") shakeAnim.fromValue = -10 shakeAnim.toValue = 10 shakeAnim.duration = 0.1 shakeAnim.repeatCount = 5 shakeAnim.autoreverses = true // THIS LINE MAKES THE ANIMATION RUN—don't skip it! layer.add(shakeAnim, forKey: "shakeAnimation") print("Shaked!") } }
If that layer.add(...) line is missing, the animation exists but never gets attached to the cell's visual layer.
2. Verify your animation's keyPath and values are valid
Typos in the keyPath or wrong value types will silently break the animation. For example:
- Wrong:
"transform.translate.x"(it'stranslation, nottranslate) - Wrong:
fromValue = "-10"(needs to be a numeric type likeCGFloat, not a string)
Stick to a tried-and-true shake setup like the example above first—get that working before tweaking values.
3. Make sure you're grabbing the correct cell in didSelectItemAt
Even though your print runs, it's worth confirming you're accessing the right cell instance. Your collection view delegate code should look like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // Guard against nil or wrong cell type guard let tacoCell = collectionView.cellForItem(at: indexPath) as? TacoCell else { print("Couldn't cast cell to TacoCell") return } tacoCell.shake() }
If the guard fails, you'd see that error print—but since your "Shaked!" line runs, this is probably okay. But it's good to rule out.
4. Check for cell reuse interfering with the animation
UICollectionView reuses cells to save memory. If you scroll the tapped cell off-screen right after tapping, the cell might get dequeued for another item, which can stop the animation mid-run. To test this:
- Keep the tapped cell on-screen after tapping—does the animation show up then?
- If yes, you can add a check to make sure the cell is still associated with the correct index path when animating, or temporarily disable reuse (not ideal for performance long-term, but good for testing).
5. Adjust animation properties for visibility
Sometimes the animation is running, but it's too subtle or fast to see. Try tweaking these values:
- Increase
durationto0.2(slower shake) - Increase
fromValue/toValueto-15/15(more dramatic movement) - Set
repeatCountto3instead of a huge number (shorter, more noticeable shake)
Start with the first fix (adding the animation to the layer)—that's almost always the culprit when print runs but animation doesn't. Once you get that working, you can tweak the animation to your liking!
内容的提问来源于stack exchange,提问作者Mohamed Farid

