CALayer宽度动画异常:从Started到Awaiting...标签的填充动画问题
Hey there! Let's figure out why your fill animation isn't behaving as expected. Looking at your code and the desired effect, there are a couple of key issues we can fix to get that smooth fill from "started" to "awaiting...".
Key Issues in Your Current Implementation
- Wrong Layer Parent: You're adding the animation layer to
ivStarted.layer, which means the layer is constrained within the bounds of the "started" label. To cover the entire area from "started" to "awaiting...", the layer should be added to the parent containerviewStartedAwaited.layerinstead. - Coordinate System Mismatch: The frame you set for the layer uses
viewStartedAwaited's origin, but since you were adding it toivStarted.layer, this puts the layer in the wrong position relative to its parent. - Redundant Animation Group: You're using a
CAAnimationGroupwith only one animation—this isn't necessary, and simplifies things to use justCABasicAnimation. - Conflicting Animation Values: Setting
fromValue,byValue, andtoValuetogether can cause unexpected behavior; stick tofromValueandtoValuefor clear control.
Fixed Implementation
func startProgressAnimation() { self.ivStarted.isHighlighted = true // Create the fill layer and add it to the container view's layer let fillLayer = CALayer() fillLayer.backgroundColor = #colorLiteral(red: 0.4980392157, green: 0.8352941176, blue: 0.1921568627, alpha: 1) fillLayer.masksToBounds = true // Set initial frame: position at the top-left of the container, height matching the container, width 0 fillLayer.frame = CGRect( x: 0, y: 0, width: 0, height: self.viewStartedAwaited.bounds.height ) self.viewStartedAwaited.layer.addSublayer(fillLayer) // Create the width animation let widthAnimation = CABasicAnimation(keyPath: "bounds.size.width") widthAnimation.fromValue = 0.0 widthAnimation.toValue = self.viewStartedAwaited.bounds.width widthAnimation.duration = 5.0 widthAnimation.isRemovedOnCompletion = false widthAnimation.fillMode = .both // Update the layer's actual width to match the animation end state (prevents snap-back) fillLayer.bounds.size.width = self.viewStartedAwaited.bounds.width CATransaction.begin() CATransaction.setCompletionBlock { [weak self] in self?.ivAwaited.isHighlighted = true } fillLayer.add(widthAnimation, forKey: "widthFillAnimation") CATransaction.commit() }
What Changed & Why
- Layer Parent Updated: The fill layer is now added to
viewStartedAwaited.layer, so it can span the entire width of the container holding both labels. - Correct Initial Frame: The layer starts at
(0, 0)relative to the container, with height matching the container—this ensures it covers the full background area we need to fill. - Simplified Animation: We removed the unnecessary animation group and focused on a single
CABasicAnimationfor width. - Persistent Layer State: We explicitly set
fillLayer.bounds.size.widthto the final value before adding the animation. This prevents the layer from snapping back to width 0 once the animation finishes, even withisRemovedOnCompletion = false.
内容的提问来源于stack exchange,提问作者Chirag Shah
相关产品推荐
相关产品推荐

