CALayer从下到上动画需求:UIImageView上接口请求进度组动画异常
解决UIImageView上WebService进度动画从下到上的问题
嘿,我之前刚好碰到过一模一样的场景!你现在的动画从顶部启动,核心原因是CALayer默认的锚点在图层中心,咱们只需要调整锚点或者用mask图层,就能轻松实现从下往上的进度效果,还能同步文本变更的动画。
方案一:使用Mask图层(推荐,灵活适配各种场景)
这种方式是给UIImageView的图层加一个遮罩,通过动画遮罩的高度来实现从下往上“揭开”原图的效果,完全贴合进度逻辑,还不会影响原图的样式(比如圆角、阴影)。
代码示例:
// 假设你的UIImageView实例叫progressImageView let maskLayer = CALayer() maskLayer.backgroundColor = UIColor.black.cgColor // 初始状态:遮罩高度为0,位置在ImageView底部,完全隐藏原图 maskLayer.frame = CGRect( x: 0, y: progressImageView.bounds.height, width: progressImageView.bounds.width, height: 0 ) progressImageView.layer.mask = maskLayer // 1. 进度动画:让遮罩高度从0增加到ImageView的高度 let progressAnim = CABasicAnimation(keyPath: "bounds.size.height") progressAnim.fromValue = 0 progressAnim.toValue = progressImageView.bounds.height progressAnim.duration = 2.0 // 替换成你的实际请求时长 progressAnim.fillMode = .forwards progressAnim.isRemovedOnCompletion = false // 2. 文本变更动画:这里以CATextLayer的淡入+文本更新为例 let textLayer = CATextLayer() textLayer.string = "加载中..." textLayer.frame = progressImageView.bounds textLayer.alignmentMode = .center textLayer.foregroundColor = UIColor.white.cgColor textLayer.fontSize = 16 progressImageView.layer.addSublayer(textLayer) let textAnim = CABasicAnimation(keyPath: "opacity") textAnim.fromValue = 0 textAnim.toValue = 1 textAnim.duration = 2.0 // 3. 组合动画:同步执行进度和文本动画 let animGroup = CAAnimationGroup() animGroup.animations = [progressAnim, textAnim] animGroup.duration = 2.0 animGroup.fillMode = .forwards animGroup.isRemovedOnCompletion = false maskLayer.add(animGroup, forKey: "progressWithTextGroup")
方案二:调整图层锚点+缩放动画
如果不想用遮罩,也可以直接修改UIImageView图层的锚点,让缩放动画从底部开始。不过要注意,锚点变更会影响图层位置,需要重置frame避免偏移。
代码示例:
// 保存原始frame,因为锚点变更会改变图层位置 let originalFrame = progressImageView.frame // 将锚点设为底部中心,这样缩放动画会从底部向上展开 progressImageView.layer.anchorPoint = CGPoint(x: 0.5, y: 1.0) // 重置frame,修正锚点变更带来的偏移 progressImageView.frame = originalFrame // 进度动画:Y轴从0缩放到1,实现从下往上的填充效果 let scaleAnim = CABasicAnimation(keyPath: "transform.scale.y") scaleAnim.fromValue = 0 scaleAnim.toValue = 1 scaleAnim.duration = 2.0 scaleAnim.fillMode = .forwards scaleAnim.isRemovedOnCompletion = false // 同步文本动画(和方案一类似) let textLayer = CATextLayer() textLayer.string = "加载中..." textLayer.frame = progressImageView.bounds textLayer.alignmentMode = .center textLayer.foregroundColor = UIColor.white.cgColor progressImageView.layer.addSublayer(textLayer) let textAnim = CABasicAnimation(keyPath: "opacity") textAnim.fromValue = 0 textAnim.toValue = 1 textAnim.duration = 2.0 // 组合动画 let animGroup = CAAnimationGroup() animGroup.animations = [scaleAnim, textAnim] animGroup.duration = 2.0 progressImageView.layer.add(animGroup, forKey: "scaleProgressGroup")
额外技巧:绑定真实WebService进度
如果要和网络请求的实时进度同步,不需要用基础动画,直接在进度回调里更新遮罩的frame即可:
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceiveData data: Data) { guard let totalBytes = dataTask.response?.expectedContentLength else { return } let receivedBytes = dataTask.countOfBytesReceived let progressRatio = CGFloat(receivedBytes) / CGFloat(totalBytes) DispatchQueue.main.async { // 计算遮罩的位置和高度:进度越高,遮罩从底部向上延伸的高度越大 self.maskLayer.frame = CGRect( x: 0, y: self.progressImageView.bounds.height * (1 - progressRatio), width: self.progressImageView.bounds.width, height: self.progressImageView.bounds.height * progressRatio ) // 同步更新文本 self.textLayer.string = String(format: "已加载%.0f%%", progressRatio * 100) } }
这样就能完美实现和网络请求进度同步的从下往上动画啦!
内容的提问来源于stack exchange,提问作者ibiren
相关产品推荐
相关产品推荐

