当我将UIPanGestureRecognizer和自动布局结合在一起时,我的UIViews变得糟糕透顶
我想要一个球跟踪我的手指,当我沿着一个圆形轨迹拖动iPhone或iPad上的每个允许的设备方向时。 当一个设备被旋转时,视图看起来是正确的居中,但是球不会停留在圆周上,当我拖动它的时候它似乎会去任何地方。
编辑
马丁R的答案现在显示这个要求。 我唯一的附加代码更改是删除不必要的声明var shapeLayer = CAShapeLayer()
这个例子中的math是非常有意义的,直到我试图将球和轨迹同时约束到视图的中心,并在运行时将球的中心坐标加上偏移量。 我遵循这些关于如何约束视图的build议 。
有三件事我不明白。
首先,根据两个variablestrackRadius
和angular度theta
计算圆的圆周,并使用theta
sin
和cos
来找出x
和y
坐标,这样就不会使球处于正确的位置。
其次,使用atan
来查看视图中心与触摸点之间的angular度theta
,使用trackRadius
和theta
来查找x
和y
坐标不会将球放置或移动到沿着圆周的新位置。
第三,每当我拖动球,在debugging区域的消息说, Xcode is Unable to simultaneously satisfy constraints
,虽然没有约束问题报告拖动之前。
这里可能有一个以上的问题。 我的大脑开始受到伤害,如果有人能指出我做错了什么,我会很感激。
这是我的代码。
import UIKit class ViewController: UIViewController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .all } var shapeLayer = CAShapeLayer() let track = ShapeView() var ball = ShapeView() var theta = CGFloat() private let trackRadius: CGFloat = 125 private let ballRadius: CGFloat = 10 override func viewDidLoad() { super.viewDidLoad() createTrack() createBall() } private func createTrack() { track.translatesAutoresizingMaskIntoConstraints = false track.shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: -trackRadius, y: -trackRadius, width: 2 * trackRadius, height: 2 * trackRadius)).cgPath track.shapeLayer.fillColor = UIColor.clear.cgColor track.shapeLayer.strokeColor = UIColor.red.cgColor view.addSubview(track) track.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true track.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true } private func createBall() { let offset = placeBallOnCircumference() drawBall() constrainBall(offset: offset) let touch = UIPanGestureRecognizer(target: self, action:#selector(dragBall(recognizer:))) view.addGestureRecognizer(touch) } private func placeBallOnCircumference() -> CGPoint { let theta: Double = 0 // at 0 radians let x = CGFloat(cos(theta)) * trackRadius // find x and y coords on let y = CGFloat(sin(theta)) * trackRadius // circle circumference return CGPoint(x: x, y: y) } func dragBall(recognizer: UIPanGestureRecognizer) { var offset = CGPoint() let finger : CGPoint = recognizer.location(in: self.view) theta = CGFloat(atan2(Double(finger.x), Double(finger.y))) // get angle from finger tip to centre offset.x = CGFloat(cos(theta)) * trackRadius // use angle and radius to get x and offset.y = CGFloat(sin(theta)) * trackRadius // y coords on circle circumference drawBall() constrainBall(offset: offset) } private func drawBall() { ball.shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 2 * ballRadius, height: 2 * ballRadius)).cgPath ball.shapeLayer.fillColor = UIColor.cyan.cgColor ball.shapeLayer.strokeColor = UIColor.black.cgColor view.addSubview(ball) } private func constrainBall(offset: CGPoint) { ball.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ ball.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: offset.x), ball.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset.y), ball.widthAnchor.constraint(equalToConstant: trackRadius), ball.heightAnchor.constraint(equalToConstant: trackRadius) ]) } }
主要的错误是
theta = CGFloat(atan2(Double(finger.x), Double(finger.y))) // get angle from finger tip to centre
不考虑视图(或跟踪) 中心 ,并且atan2()
的参数是错误的(y先出现)。 它应该是:
theta = atan2(finger.y - track.center.y, finger.x - track.center.x)
另一个问题是你在func constrainBall()
添加了越来越多的func constrainBall()
,而没有删除以前的那些。 你应该保持对约束的引用,并修改它们。
最后请注意,球的宽度/高度约束应该是2*ballRadius
,而不是trackRadius
。
把它放在一起(并删除一些不必要的types转换),它会看起来像这样:
var ballXconstraint: NSLayoutConstraint! var ballYconstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() createTrack() createBall() let touch = UIPanGestureRecognizer(target: self, action:#selector(dragBall(recognizer:))) view.addGestureRecognizer(touch) } private func createTrack() { track.translatesAutoresizingMaskIntoConstraints = false track.shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 2 * trackRadius, height: 2 * trackRadius)).cgPath track.shapeLayer.fillColor = UIColor.clear.cgColor track.shapeLayer.strokeColor = UIColor.red.cgColor view.addSubview(track) track.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true track.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true track.widthAnchor.constraint(equalToConstant: 2 * trackRadius).isActive = true track.heightAnchor.constraint(equalToConstant: 2 * trackRadius).isActive = true } private func createBall() { // Create ball: ball.translatesAutoresizingMaskIntoConstraints = false ball.shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 2 * ballRadius, height: 2 * ballRadius)).cgPath ball.shapeLayer.fillColor = UIColor.cyan.cgColor ball.shapeLayer.strokeColor = UIColor.black.cgColor view.addSubview(ball) // Width/Height contraints: ball.widthAnchor.constraint(equalToConstant: 2 * ballRadius).isActive = true ball.heightAnchor.constraint(equalToConstant: 2 * ballRadius).isActive = true // X/Y constraints: let offset = pointOnCircumference(0.0) ballXconstraint = ball.centerXAnchor.constraint(equalTo: track.centerXAnchor, constant: offset.x) ballYconstraint = ball.centerYAnchor.constraint(equalTo: track.centerYAnchor, constant: offset.y) ballXconstraint.isActive = true ballYconstraint.isActive = true } func dragBall(recognizer: UIPanGestureRecognizer) { let finger = recognizer.location(in: self.view) // Angle from track center to touch location: theta = atan2(finger.y - track.center.y, finger.x - track.center.x) // Update X/Y contraints of the ball: let offset = pointOnCircumference(theta) ballXconstraint.constant = offset.x ballYconstraint.constant = offset.y } private func pointOnCircumference(_ theta: CGFloat) -> CGPoint { let x = cos(theta) * trackRadius let y = sin(theta) * trackRadius return CGPoint(x: x, y: y) }
- 仅UIScrollView自动布局垂直
- 我有一个UILabel自动布局定位在屏幕上,但是当我隐藏导航栏,它会导致标签“抽搐”第二个
- AutoLayout和UILabel调整animation在设备旋转时无法正常工作
- 带有AutoLayout的UICollectionView Cell + UiLabel
- 每当我的应用程序启动时,为什么我会在执行“-layoutSubviews”后仍然需要“自动布局”?
- 在iPhone上使用Xcode Auto Layout来设置不同的图像尺寸
- 使用自定义animation时,会在iOS9上忽略edgesForExtendedLayout
- 在视图控制器的宽度上水平均匀分布UIButton的最简单的方法是什么?
- closures“使用Autolayout”导致应用程序只能在纵向模式下运行