You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CGAffineTransform旋转视图仅首次生效,后续无动画如何解决?

解决自定义视图重复旋转动画失效及应用冻结问题

问题根源

你当前代码存在两个核心问题:

  • 动画触发条件缺失:每次动画都将视图的transform重置为「相对于原始状态旋转90度」,第一次旋转后视图的transform已经是这个值,后续再设置相同的属性值,UIKit检测不到变化,自然不会触发动画。
  • 高频递归阻塞主线程:由于动画未实际执行,completion闭包会立刻触发,导致_rotateSelf()被高频递归调用,最终阻塞主线程造成应用冻结。

修正后的代码

private func _rotateSelf(duration: Double = 1.0, delay: Double = 3.0) {
    print("self._rotateSelf() called from UICustomView")
    
    UIView.animate(withDuration: duration, delay: delay, options: [.curveEaseInOut], animations: {
        // 在上一次的旋转状态基础上继续旋转90度
        self.transform = self.transform.rotated(by: .pi / 2)
    }, completion: { finished in
        if finished {
            print("Animation finished")
            self._rotateSelf()
        }
    })
}

关键修改说明

将CGAffineTransform.identity.rotated(by: .pi/2)改为self.transform.rotated(by: .pi/2),每次旋转都基于视图当前的transform状态叠加90度,确保transform属性每次都有有效变化,UIKit会正常触发动画。同时,动画真正完成后才会递归调用,避免了高频递归导致的主线程阻塞。

可选优化方案(避免递归)

如果需要更灵活地控制旋转启停,推荐使用定时器替代递归:

private var rotationTimer: Timer?

// 启动旋转
func startRotating() {
    rotationTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: true) { [weak self] _ in
        guard let self = self else { return }
        UIView.animate(withDuration: 1.0, options: .curveEaseInOut) {
            self.transform = self.transform.rotated(by: .pi / 2)
        }
    }
}

// 停止旋转
func stopRotating() {
    rotationTimer?.invalidate()
    rotationTimer = nil
}

内容的提问来源于stack exchange,提问作者user4496950

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 11:22:49