Swift CGAffineTransform 旋转跳跃
Swift CGAffineTransform rotation jumps
我在自己的项目中使用了 How to rotate an UIImageView using TouchesMoved 中的信息。但是我发现了一个问题,我想不出如何解决它。
原post中的视图也有同样的问题,但小视图几乎不明显。 A做了这个示例代码。查看视图如何“跳跃”。触摸点始终位于锚点的左侧。我怎样才能避免这种跳跃。
class ViewController: UIViewController {
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
myView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 200))
myView.center = self.view.center
myView.isUserInteractionEnabled = true
myView.backgroundColor = UIColor.red
self.view.addSubview(myView)
myView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.0)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
if touch.view === myView {
let position = touch.location(in: self.view)
let target = myView.center
let angle = atan2(target.y-position.y, target.x-position.x)
myView.transform = CGAffineTransform(rotationAngle: angle)
}
}
}
看来你的问题在行
let angle = atan2(target.y-position.y, target.x-position.x)
atan2 returns0到π之间的一个数,而不是你想要的,-π到π之间的一个数。您应该能够通过将 (target.y - position.y)
与 0 进行比较来修复它。当它大于零时,您的原始返回值应该是好的。当它小于零时,你会想要减去 π 以获得正确的角度。
你有两个主要问题:
您没有考虑原始触摸的位置。您需要在 touchesBegan
中记录该信息并计算出相对于该信息的旋转变换角度。
你说 let target = myView.center
好像这是我们旋转的点。但它不是,因为你移动了 myView
的 anchorPoint
。
这是工作代码(取自我的书),可让您拖动以围绕其自身中心旋转 myView
:
class ViewController: UIViewController {
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
myView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 200))
myView.center = self.view.center
myView.isUserInteractionEnabled = true
myView.backgroundColor = UIColor.red
self.view.addSubview(myView)
}
func pToA (_ t:UITouch) -> CGFloat {
let loc = t.location(in: myView)
let c = myView.convert(myView.center, from:myView.superview!)
return atan2(loc.y - c.y, loc.x - c.x)
}
var initialAngle = CGFloat(0)
var angle = CGFloat(0)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.initialAngle = pToA(touches.first!)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let ang = pToA(touches.first!) - self.initialAngle
let absoluteAngle = self.angle + ang
myView.transform = myView.transform.rotated(by: ang)
self.angle = absoluteAngle
}
}
但是如果您真的想围绕不同的点旋转(像您的代码那样移动锚点),则需要相应地调整该代码。
我在自己的项目中使用了 How to rotate an UIImageView using TouchesMoved 中的信息。但是我发现了一个问题,我想不出如何解决它。
原post中的视图也有同样的问题,但小视图几乎不明显。 A做了这个示例代码。查看视图如何“跳跃”。触摸点始终位于锚点的左侧。我怎样才能避免这种跳跃。
class ViewController: UIViewController {
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
myView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 200))
myView.center = self.view.center
myView.isUserInteractionEnabled = true
myView.backgroundColor = UIColor.red
self.view.addSubview(myView)
myView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.0)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
if touch.view === myView {
let position = touch.location(in: self.view)
let target = myView.center
let angle = atan2(target.y-position.y, target.x-position.x)
myView.transform = CGAffineTransform(rotationAngle: angle)
}
}
}
看来你的问题在行
let angle = atan2(target.y-position.y, target.x-position.x)
atan2 returns0到π之间的一个数,而不是你想要的,-π到π之间的一个数。您应该能够通过将 (target.y - position.y)
与 0 进行比较来修复它。当它大于零时,您的原始返回值应该是好的。当它小于零时,你会想要减去 π 以获得正确的角度。
你有两个主要问题:
您没有考虑原始触摸的位置。您需要在
touchesBegan
中记录该信息并计算出相对于该信息的旋转变换角度。你说
let target = myView.center
好像这是我们旋转的点。但它不是,因为你移动了myView
的anchorPoint
。
这是工作代码(取自我的书),可让您拖动以围绕其自身中心旋转 myView
:
class ViewController: UIViewController {
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
myView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 200))
myView.center = self.view.center
myView.isUserInteractionEnabled = true
myView.backgroundColor = UIColor.red
self.view.addSubview(myView)
}
func pToA (_ t:UITouch) -> CGFloat {
let loc = t.location(in: myView)
let c = myView.convert(myView.center, from:myView.superview!)
return atan2(loc.y - c.y, loc.x - c.x)
}
var initialAngle = CGFloat(0)
var angle = CGFloat(0)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.initialAngle = pToA(touches.first!)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let ang = pToA(touches.first!) - self.initialAngle
let absoluteAngle = self.angle + ang
myView.transform = myView.transform.rotated(by: ang)
self.angle = absoluteAngle
}
}
但是如果您真的想围绕不同的点旋转(像您的代码那样移动锚点),则需要相应地调整该代码。