Как установить границы элемента управления перетаскиванием с помощью UIPanGestureRecognizer? - PullRequest
1 голос
/ 03 апреля 2019

У меня есть View, внутри которого я добавляю Label, затем я пытался установить границу для перемещения Label с помощью PanGesture.Ниже приведен мой код:

@objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
        let translation = gestureRecognizer.translation(in: self)
        if let view = gestureRecognizer.view {

            if (view.frame.origin.x + translation.x >= 0) && (view.frame.origin.y + translation.y >= 0) && (view.frame.origin.x + translation.x <= view.frame.width) && (view.frame.origin.y + translation.y <= view.frame.height)
            {
                view.center = CGPoint(x:view.center.x + translation.x,
                                       y:view.center.y + translation.y)
            }
        }
        gestureRecognizer.setTranslation(CGPoint.zero, in: self)
    }

}

Я взял ссылку на этот ответ: https://stackoverflow.com/a/49008808/9970928

Но он не работает, кто-нибудь может сказать, что мне не хватает в состоянии?

1 Ответ

2 голосов
/ 03 апреля 2019

Код не самый интуитивно понятный, но при условии, что все остальное работает, проблема в том, что он выходит за пределы только справа и снизу.Посмотрите на ваше состояние с помощью:

(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)
        }

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...