Je sous-classe UIView
et j'essaye de "faire glisser" un CGRect
d'avant en arrière sur l'écran. En gros, je veux déplacer (redessiner) le rectangle chaque fois que je fais glisser mon doigt. Jusqu'à présent, j'ai ce code:
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) }
C'est la première fois que j'utilise UIPanGestureRecognizer
, donc je ne suis pas sûr de tous les détails qui entrent dans ce domaine. J'ai défini des points d'arrêt dans drawRectangle
et confirmé que cela est appelé. Cependant, le rectangle à l'écran ne bouge pas du tout, peu importe le nombre de fois que j'essaye de le faire glisser. Quel est le problème?
3 Réponses :
Essayez comme ceci (vérifiez les commentaires via le code):
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 } } }
extension CGPoint { static func +=(lhs: inout CGPoint, rhs: CGPoint) { lhs.x += rhs.x lhs.y += rhs.y } }
Pour dessiner des rectangles sur votre vue lors du panoramique, vous pouvez faire comme suivez:
@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) } }
Salut, merci pour la réponse. Je suis très proche de faire ce travail (voir ma propre réponse), mais j'ai encore besoin d'un peu d'aide pour que le rectangle "anime".
Je pense qu'il devrait être relativement simple de le faire fonctionner dans une sous-classe UIView au lieu d'un contrôleur. Vous pouvez utiliser l'exemple de projet ci-dessus comme point de départ. Si vous rencontrez des problèmes, faites-le moi savoir
Voici comment procéder facilement. copiez-collez et exécutez ceci.
// // 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)") } }voici la démo,
J'espère que cela vous aidera. bravo!
Salut, merci pour la réponse. Cependant, je voudrais effectuer un dessin personnalisé dans ma sous-classe de UIView
. Pensez-vous que c'est possible?
@Xcoder vérifiez la réponse mise à jour stackoverflow.com/a/56729268/2303865 et un exemple de projet où vous pouvez également dessiner et faire glisser dropbox.com/s/48mklm2t1jyo1x3/Draggable%20Rectangle.zip? dl = 1
@LeoDabus Merci beaucoup, mais que ferais-je si je veux coder dans une sous-classe de UIView
?
Salut, merci pour la réponse. Je suis très proche de faire ce travail (voir ma propre réponse), mais j'ai encore besoin d'un peu d'aide pour que le rectangle "anime".
J'ai compris la plupart du problème de savoir pourquoi le rectangle ne bougeait pas. Il s'avère que j'ai mal compris comment fonctionnent les getters et les setters variables dans Swift. Néanmoins, j'ai changé ce code:
rectangle = CGRect(x: rectangle.minX + translation.x, y: rectangle.minY + translation.y, width: rectangle.width, height: rectangle.height)
pour être une variable paresseuse
:
rectangle = CGRect(x: rectangle.midX + translation.x, y: rectangle.midY + translation.y, width: rectangle.width, height: rectangle.height)
La raison pour laquelle j'avais besoin get
et set
en premier lieu était dû au fait que j'utilisais frame
dans mes calculs de variables, et cela n'était pas disponible tant que la vue elle-même n'était pas complètement instanciée . J'ai également modifié un peu ce code:
lazy var rectangle: CGRect = { return CGRect(x: 200, y: 200, width: self.frame.width / 6, height: 15) }()
et utilisé minX
au lieu de midX
:
var rectangle: CGRect { get { return CGRect(x: 200, y: 200, width: frame.width / 6, height: 15) } set {} }
Ceci est dû au fait que CGRect
est initialisé avec les paramètres x et y étant les minX
et minY
. p>
C'est une bonne progression (au moins le rectangle se déplace). Cependant, je ne suis pas en mesure de comprendre pourquoi le rectangle ne change de place qu'après avoir relâché ma souris, ce qui entraîne un mouvement saccadé.
N'ajoutez pas UIPanGestureRecognizer dans la méthode
draw
, ajoutez-le à la méthode init. Ou le geste sera ajouté plusieurs fois.