SwiftUI:旋转后便签拖拽运动异常问题
SwiftUI:旋转后便签拖拽运动异常问题
嘿,我太懂你这个烦恼了——旋转便签之后拖拽方向完全不对劲儿,明明想往上拖结果它往侧边跑,这事儿确实挺折腾人的!
其实问题的核心很简单:SwiftUI的rotationEffect只是做了视觉层面的旋转,但手势识别的坐标系还是绑定视图原始的未旋转状态。也就是说,拖拽手势返回的translation值,是基于便签没旋转时的x/y轴计算的,等便签转了角度,自然就和你视觉预期的拖拽方向对不上了。
要解决这个问题,我们需要把拖拽得到的原始平移向量,根据便签的旋转角度做一次逆旋转变换——把原始坐标系的平移量,转换成旋转后视图本地坐标系的平移量,这样更新位置的时候就会和视觉方向匹配了。
具体步骤和代码修改:
- 先写一个辅助方法,用来对平移向量进行逆旋转计算
这个方法会用三角函数把原始的x/y平移,转换成适配旋转角度的新平移量:
func inverseRotateTranslation(_ translation: CGSize, by angleRadians: Double) -> CGSize { let cosAngle = cos(CGFloat(angleRadians)) let sinAngle = sin(CGFloat(angleRadians)) // 逆旋转矩阵运算:将原始坐标系的平移映射到旋转后坐标系 let transformedX = translation.width * cosAngle + translation.height * sinAngle let transformedY = -translation.width * sinAngle + translation.height * cosAngle return CGSize(width: transformedX, height: transformedY) }
注意:如果你的便签模型里存的旋转角度是度数(比如0-360),记得先转换成弧度再传进来,比如
Double(angleDegrees) * .pi / 180
- 在拖拽手势里用这个方法修正平移量
把原来直接用value.translation更新位置的逻辑,改成用变换后的平移量:
.gesture( DragGesture() .onChanged { value in var updatedSticky = self.stickyNote // 对原始拖拽平移做逆旋转修正 let adjustedTranslation = inverseRotateTranslation(value.translation, by: updatedSticky.rotation) // 用修正后的平移更新便签位置 updatedSticky.position = CGPoint( x: updatedSticky.position.x + adjustedTranslation.width, y: updatedSticky.position.y + adjustedTranslation.height ) self.stickyNote = updatedSticky } )
- 把修正后的逻辑整合到你的原代码里
比如你的ZStack可以调整成这样:
ZStack { stickyNote.color .frame(width: stickyNote.size.width, height: stickyNote.size.height) .cornerRadius(10) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(isSelected ? Color.blue : Color.clear, lineWidth: 2) ) .position(stickyNote.position) .rotationEffect(Angle(radians: stickyNote.rotation)) .gesture( DragGesture() .onChanged { value in var updatedSticky = self.stickyNote let adjustedTranslation = inverseRotateTranslation(value.translation, by: updatedSticky.rotation) updatedSticky.position = CGPoint( x: updatedSticky.position.x + adjustedTranslation.width, y: updatedSticky.position.y + adjustedTranslation.height ) self.stickyNote = updatedSticky } ) }
额外小提示:
你可以在调试的时候,打印一下value.translation和adjustedTranslation的数值,对比看看变换是否符合预期——比如当便签旋转90度时,原始拖拽的y轴平移应该会被转换成x轴的平移,这样你往上拖拽的时候,便签就会向视觉上的“上方”移动了。
备注:内容来源于stack exchange,提问作者Menslo
相关产品推荐
相关产品推荐

