Swift中UIView无法绕Z轴正常旋转的问题求助
UIView绕Z轴旋转异常问题
我在Swift中尝试让UIView绕Z轴旋转,但旋转轴不符合预期:

当前使用的代码:
rotatedView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) rotatedView.contentMode = .scaleToFill rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1)
如何让UIView正确绕Z轴旋转?感谢解答。
更新1:控件控制差异排查
经排查发现,使用Stepper控件控制旋转时,视图是正常绕Z轴旋转的。代理函数delegate?.didRotateObject会更新rotatedObjectWrapper.object.rotation的值。
Slider控制代码:
@IBAction func didChangeRotation(_ sender: UISlider) { delegate?.didRotateObject(to: Double(angleSlider.value)) }
Stepper控制代码(每次更新0.1弧度):
@IBAction func didChangeStepper(_ sender: Any) { delegate?.didRotateObject(to: Double(stepper.value)) }
尝试添加动画修改旋转值,视图看似绕Z轴旋转,但仍存在异常行为:
UIView.animate(withDuration: 0.5, animations: { rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1) })
动画后的效果:
更新2:对比测试
我创建了一个测试视图testView,它能正常绕Z轴旋转,但从字典objectsToViews中获取的rotatedView旋转仍异常,两者代码逻辑一致:
testView = CustomObjectView(image: UIImage(named: "black")) guard let testView = testView else { return } testView.frame = CGRect(x: rotatedObject.position.x, y: rotatedObject.position.y, width: rotatedObject.width, height: rotatedObject.height) testView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1) rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1) print(testView.layer.frame) print(rotatedView.layer.frame) rotatedView.layer.frame = testView.layer.frame print(rotatedView.layer.frame) print(")))))))")
rotatedView的获取方式:
guard let rotatedView = objectsToViews[rotatedObjectWrapper] else { return }
强行设置rotatedView.layer.frame与testView.layer.frame一致,问题仍未解决。
解决方案
1. 排查字典中视图的初始状态
新创建的testView正常旋转,但字典中的rotatedView异常,大概率是这个视图存入字典前已被设置非默认的变换、布局属性:
- 检查
objectsToViews存储rotatedView时,是否已设置过非默认的layer.transform、anchorPoint或bounds; - 确认
rotatedView的父视图布局是否稳定,是否存在自动布局导致的frame异常。
2. 重置变换后再应用旋转
设置新旋转前,先重置layer变换,避免旧变换叠加导致异常:
// 先重置变换为默认状态 rotatedView.layer.transform = CATransform3DIdentity // 再应用目标旋转 rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1)
3. 改用bounds+position控制视图位置
直接修改layer.frame在有变换的场景下易出问题,建议通过bounds和position控制位置:
// 先重置变换 rotatedView.layer.transform = CATransform3DIdentity // 同步测试视图的尺寸与位置 rotatedView.layer.bounds = testView.layer.bounds rotatedView.layer.position = testView.layer.position // 再应用旋转 rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1)
4. Slider控制改用增量更新
Slider是连续取值,易导致变换叠加异常,可基于当前旋转值做增量更新:
// 先声明属性记录当前旋转值:var currentRotation: Double = 0.0 @IBAction func didChangeRotation(_ sender: UISlider) { let targetRotation = Double(sender.value) let delta = targetRotation - currentRotation // 基于当前变换做增量旋转 rotatedView.layer.transform = CATransform3DRotate(rotatedView.layer.transform, delta, 0, 0, 1) currentRotation = targetRotation // 同步更新数据模型 delegate?.didRotateObject(to: targetRotation) }
5. 修正anchorPoint设置顺序
设置anchorPoint会影响视图位置,需先记录当前中心位置再恢复:
// 先记录当前中心 let currentCenter = rotatedView.center // 设置锚点为中心 rotatedView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5) // 恢复中心位置 rotatedView.center = currentCenter // 再应用旋转 rotatedView.layer.transform = CATransform3DMakeRotation(rotatedObjectWrapper.object.rotation, 0, 0, 1)
内容的提问来源于stack exchange,提问作者Taufiq Bin Abdul Rahman
相关产品推荐
相关产品推荐

