Код не самый интуитивно понятный, но при условии, что все остальное работает, проблема в том, что он выходит за пределы только справа и снизу.Посмотрите на ваше состояние с помощью:
(view.frame.origin.x + translation.x <= view.frame.width)
(view.frame.origin.y + translation.y <= view.frame.height)
Итак, это говорит о том, что начало координат может быть не больше размера границ. Вам нужно проверить максимальные значения внутреннего представления:
(view.frame.maxX + translation.x <= view.frame.width)
(view.frame.maxY + translation.y <= view.frame.height)
Но эта процедура в целом может вызвать проблемы.Представьте, что пользователь очень быстро проводит вправо.И что максимум center.x
может быть 100
.Текущий center.x
равен 50
, и пользователь перетаскивает его в одном кадре до 200
.Ваше состояние не будет выполнено, и ваш ярлык останется на 50
вместо 100
.Я бы пошел с закреплением рамки к границам.
Что-то вроде следующего должно сделать:
func clampFrame(_ frame: CGRect, inBounds bounds: CGRect) -> CGRect {
let center: CGPoint = CGPoint(x: max(bounds.minX + frame.width*0.5, min(frame.midX, bounds.maxX - frame.width*0.5)),
y: max(bounds.minY + frame.height*0.5, min(frame.midY, bounds.maxY - frame.height*0.5)))
return CGRect(x: center.x-frame.width*0.5, y: center.y-frame.height*0.5, width: frame.width, height: frame.height)
}
func moveFrame(_ frame: CGRect, by translation: CGPoint, constrainedTo bounds: CGRect) -> CGRect {
var newFrame = frame
newFrame.origin.x += translation.x
newFrame.origin.y += translation.y
return clampFrame(newFrame, inBounds: bounds)
}
Могут быть и другие проблемы, использующие процедуру "перевода".Я бы пошел с поиском местоположения в поле зрения.Пожалуйста, смотрите следующий рабочий пример:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myView = MyView(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 200.0))
myView.backgroundColor = UIColor.green
view.addSubview(myView)
let label = UILabel(frame: .zero)
label.backgroundColor = UIColor.blue.withAlphaComponent(0.2)
label.font = UIFont.systemFont(ofSize: 50.0)
label.text = "Hi!"
label.sizeToFit()
myView.addSubview(label)
label.addGestureRecognizer(UIPanGestureRecognizer(target: myView, action: #selector(MyView.handlePan)))
label.isUserInteractionEnabled = true
}
}
class MyView: UIView {
func clampFrame(_ frame: CGRect, inBounds bounds: CGRect) -> CGRect {
let center: CGPoint = CGPoint(x: max(bounds.minX + frame.width*0.5, min(frame.midX, bounds.maxX - frame.width*0.5)),
y: max(bounds.minY + frame.height*0.5, min(frame.midY, bounds.maxY - frame.height*0.5)))
return CGRect(x: center.x-frame.width*0.5, y: center.y-frame.height*0.5, width: frame.width, height: frame.height)
}
func moveFrame(_ frame: CGRect, by translation: CGPoint, constrainedTo bounds: CGRect) -> CGRect {
var newFrame = frame
newFrame.origin.x += translation.x
newFrame.origin.y += translation.y
return clampFrame(newFrame, inBounds: bounds)
}
private var startLocation: CGPoint = .zero
private var startFrame: CGRect = .zero
@objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let label = gestureRecognizer.view else { return }
if gestureRecognizer.state == .began {
startLocation = gestureRecognizer.location(in: self)
startFrame = label.frame
} else if gestureRecognizer.state == .changed {
let newLocation = gestureRecognizer.location(in: self)
let translation = CGPoint(x: newLocation.x-startLocation.x, y: newLocation.y-startLocation.y)
label.frame = moveFrame(startFrame, by: translation, constrainedTo: self.bounds)
}
}
}