Перетащите CGRect с помощью UIPanGestureRecognizer - PullRequest
1 голос
/ 24 июня 2019

Я создаю подкласс UIView и пытаюсь «перетащить» CGRect вперед и назад по экрану. По сути, я хочу перемещать (перерисовывать) прямоугольник каждый раз, когда я перетаскиваю палец. Пока у меня есть этот код:

var rectangle: CGRect {
    get {
        return CGRect(x: 200,
                    y: 200,
                    width: frame.width / 6,
                    height: 15)
    }

    set {}
}

override func draw(_ rect: CGRect) {
    let gesture = UIPanGestureRecognizer(target: self, action: #selector(dragRectangle(recognizer:)))
    addGestureRecognizer(gesture)
    drawRectangle(rect)
}

func drawRectangle(_ rect: CGRect) {
    let path = UIBezierPath(rect: rectangle)
    UIColor.black.set()
    path.fill()
}

@objc func dragRectangle(recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translation(in: self)
    rectangle = CGRect(x: rectangle.midX + translation.x, y: rectangle.midY + translation.y, width: rectangle.width, height: rectangle.height)
    setNeedsDisplay()
    recognizer.setTranslation(CGPoint.zero, in: self)
}

Я впервые использую UIPanGestureRecognizer, поэтому я не уверен во всех деталях, которые касаются этого. Я установил точки останова в drawRectangle и подтвердил, что это вызывается. Однако прямоугольник на экране вообще не двигается, независимо от того, сколько раз я пытаюсь его перетащить. Что не так?

Ответы [ 3 ]

2 голосов
/ 24 июня 2019

Вот как вы можете сделать это легко.просто скопируйте и запустите это.

//
//  RootController.swift
//  SampleApp
//
//  Created by Chanaka Caldera on 24/6/19.
//  Copyright © 2019 homeapps. All rights reserved.
//

import UIKit

class RootController: UIViewController {

    private var draggableView: UIView!
    private var pangesture: UIPanGestureRecognizer!

    override func viewDidLoad() {
        super.viewDidLoad()

        setdragview()

    }
}

extension RootController {
    fileprivate func setdragview() {
        draggableView = UIView()
        draggableView.translatesAutoresizingMaskIntoConstraints = false
        draggableView.backgroundColor = .lightGray
        view.addSubview(draggableView)

        let draggableviewConstraints = [draggableView.leftAnchor.constraint(equalTo: view.leftAnchor,constant: 10),
                                        draggableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 64),
                                        draggableView.widthAnchor.constraint(equalToConstant: 100),
                                        draggableView.heightAnchor.constraint(equalToConstant: 40)]

        NSLayoutConstraint.activate(draggableviewConstraints)

        pangesture = UIPanGestureRecognizer()
        draggableView.isUserInteractionEnabled = true
        draggableView.addGestureRecognizer(pangesture)
        pangesture.addTarget(self, action: #selector(draggableFunction(_:)))

    }
}

extension RootController {
    @objc fileprivate func draggableFunction(_ sender: UIPanGestureRecognizer) {
        view.bringSubviewToFront(draggableView)
        let translation = sender.translation(in: self.view)
        draggableView.center = CGPoint(x: draggableView.center.x + translation.x, y: draggableView.center.y + translation.y)
        sender.setTranslation(CGPoint.zero, in: self.view)
        print("drag works : \(translation.x)")
    }
}

вот демо,

enter image description here

Надеюсь, что этопоможет.ура!

1 голос
/ 24 июня 2019

Попробуйте так (проверьте комментарии по коду):

@IBDesignable
class Rectangle: UIView {

    @IBInspectable var color: UIColor = .clear {
        didSet { backgroundColor = color }
    }
    // draw your view using the background color
    override func draw(_ rect: CGRect) {
        backgroundColor?.set()
        UIBezierPath(rect: rect).fill()
    }
    // add the gesture recognizer to your view
    override func didMoveToSuperview() {
        addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(pan)))
    }
    // your gesture selector
    @objc func pan(_ gesture: UIPanGestureRecognizer) {
        //  update your view frame origin
        frame.origin += gesture.translation(in: self)  
        // reset the gesture translation
        gesture.setTranslation(.zero, in: self)
    }
}

extension CGPoint {
    static func +=(lhs: inout CGPoint, rhs: CGPoint) {
        lhs.x += rhs.x
        lhs.y += rhs.y
    }
}

Чтобы нарисовать прямоугольники на вашем виде при панорамировании, вы можете сделать следующее:

import UIKit

class ViewController: UIViewController {
    var rectangles: [Rectangle] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(pan)))
    }
    @objc func pan(_ gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .began:
            let rectangle = Rectangle(frame: .init(origin: gesture.location(in: view), size: .init(width: 0, height: 0)))
            rectangle.fillColor = .red
            rectangle.strokeColor = .white
            rectangle.lineWidth = 3
            view.addSubview(rectangle)
            rectangles.append(rectangle)
        case .changed:
            let distance = gesture.translation(in: view)
            let index = rectangles.index(before: rectangles.endIndex)
            let frame = rectangles[index].frame
            rectangles[index].frame = .init(origin: frame.origin, size: .init(width: frame.width + distance.x, height: frame.height + distance.y))
            rectangles[index].setNeedsDisplay()
            gesture.setTranslation(.zero, in: view)
        case .ended:
            break
        default:
            break
        }
    }
}

Пример проекта

0 голосов
/ 25 июня 2019

Я выяснил большую часть проблемы относительно того, почему прямоугольник не двигался. Оказывается, я неправильно понял, как работают переменные и сеттеры в Swift. Тем не менее, я изменил этот код:

var rectangle: CGRect {
    get {
        return CGRect(x: 200,
                    y: 200,
                    width: frame.width / 6,
                    height: 15)
    }

    set {}
}

будет lazy переменной:

lazy var rectangle: CGRect = {
    return CGRect(x: 200,
                         y: 200,
                         width: self.frame.width / 6,
                         height: 15)
}()

Причина, по которой мне сначала понадобились get и set, заключалась в том, что я использовал frame в своих вычислениях переменных, и это было недоступно до полного создания экземпляра самого представления. Я также немного подправил этот код:

rectangle = CGRect(x: rectangle.midX + translation.x, y: rectangle.midY + translation.y, width: rectangle.width, height: rectangle.height)

и использовал minX вместо midX:

rectangle = CGRect(x: rectangle.minX + translation.x, y: rectangle.minY + translation.y, width: rectangle.width, height: rectangle.height)

Это потому, что CGRect инициализируется с параметрами x и y, равными minX и minY.

Это хороший прогресс (по крайней мере, прямоугольник движется). Однако я не могу понять, почему прямоугольник меняет местами только после того, как отпустил мышь, что приводит к прерывистому движению.

...