Ich habe Probleme beim Abrufen der aktuellen Position einer Ansicht, absolut im iPhone-Bildschirm, wenn die Ansicht skaliert wird. Hier ist ein minimales Beispiel von dem, was ich getan habe.Abrufen der richtigen Position einer skalierten UIView
Ich habe eine einzige elliptische Ansicht auf dem Bildschirm. Wenn ich tippe, wächst es und beginnt zu zittern, um zu zeigen, dass es ausgewählt ist. Dann kann ich die Ansicht über den ganzen Bildschirm ziehen.
Hier ist der Code:
Viewcontroller
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// The View
let toDrag = MyView(frame: CGRect(x: 0, y: 0, width: 50, height: 40))
toDrag.center = CGPoint(x:100, y:100)
// The gesture recognizer
let panGestRec = UIPanGestureRecognizer(target: self, action:#selector(self.panView(sender:)))
toDrag.addGestureRecognizer(panGestRec)
self.view.addSubview(toDrag)
}
func panView(sender: UIPanGestureRecognizer) {
guard let senderView = sender.view else { return }
if sender.state == .recognized { print("Pan Recognized", terminator:"")}
if sender.state == .began { print("Pan began", terminator: "") }
if sender.state == .changed { print("Pan changed", terminator: "") }
if sender.state == .ended { print("Pan ended", terminator: "") }
let point = senderView.convert(senderView.center, to: nil)
print (" point \(point)")
let translation = sender.translation(in: self.view)
senderView.center = CGPoint(x: senderView.center.x + translation.x, y: senderView.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: self.view)
}
}
MyView
import UIKit
class MyView: UIView {
var isAnimated: Bool = false
override init(frame: CGRect) {
super.init(frame: frame) // calls designated initializer
self.isOpaque = false
self.backgroundColor = UIColor.clear
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.isOpaque = false
self.backgroundColor = UIColor.clear
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isAnimated = true
rotate1()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isAnimated = false
endRotation()
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
isAnimated = false
endRotation()
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {return}
context.addEllipse(in: rect)
context.setLineWidth(1.0)
context.setStrokeColor(UIColor.black.cgColor)
context.setFillColor(UIColor.red.cgColor)
context.drawPath(using: .fillStroke)
}
func rotate1() {
guard isAnimated else { return }
UIView.animate(withDuration: 0.05, delay:0.0, options: [], animations: {
self.transform = CGAffineTransform.init(rotationAngle:.pi/16).scaledBy(x: 1.5, y: 1.5)
}, completion: { _ in
self.rotate2()
})
}
func rotate2() {
guard isAnimated else { return }
UIView.animate(withDuration: 0.05, delay:0.0, options: [], animations: {
self.transform = CGAffineTransform.init(rotationAngle:.pi/(-16)).scaledBy(x: 1.5, y: 1.5)
}, completion: { _ in
self.rotate1()
})
}
func endRotation() {
// End existing animation
UIView.animate(withDuration: 0.5, delay:0.0, options: .beginFromCurrentState, animations: {
self.transform = CGAffineTransform.init(rotationAngle:0).scaledBy(x: 1, y: 1)
}, completion: nil)
}
}
Mit dieser Version sind hier einige Anzeigen der Position
Pan began point (233.749182687299, 195.746572421573)
Pan changed point (175.265022520054, 181.332358181369)
Pan changed point (177.265022520054, 184.332358181369)
Pan changed point (177.265022520054, 184.332358181369)
Pan changed point (178.265022520054, 185.332358181369)
Pan changed point (179.265022520054, 186.332358181369)
Pan changed point (180.265022520054, 187.332358181369)
Pan changed point (180.265022520054, 188.332358181369)
Pan changed point (181.265022520054, 188.332358181369)
Pan RecognizedPan ended point (181.265022520054, 189.332358181369)
Sie können sehen, dass die erste Position (Anfangspunkt) nicht korrekt ist: Die Ansicht wurde in diesem Moment animiert. Die anderen Positionen sind in Ordnung, beim Ziehen wird die Ansicht nicht animiert.
Wenn ich den Code in rotate1 und rotate2 kommentiere, sind alle Positionen korrekt, also nehme ich an, dass die Dimensionierung und eventuell die Rotation der Ansicht das Ergebnis stört. Meine Frage ist: Wie kann ich die richtige Position der Ansicht abrufen, wenn sie skaliert ist? Offensichtlich ist die Linie
senderView.convert (senderView.center, zu: nil)
nicht machen, was ich dachte: Umwandlung der auf die festen Größe Bildschirmkoordinaten koordinieren?
Wenn Sie die Transformation einer Ansicht ändern, wird der Rahmen ungültig, aber das Zentrum sollte immer noch korrekt sein. Ich glaube, wenn Sie die Ansicht übersetzen, wird auch der Mittelpunkt übersetzt, aber ich bin nicht davon überzeugt. Es ist ein bisschen schwer, den Daten zu folgen, die du zeigst und zu erzählen, was passiert. –
Ich erkläre meine Ziele: In der Tat ist die Ansicht ein Pfand, und der Bildschirm ist ein Brett. Ich wollte also wissen, wo sich der Bauer bewegt und wo er endet. Die Animation dient nur dazu, visuell zu prüfen, ob der gute Bauer ausgewählt wurde. Die Quellen sind vollständig: Sie können ein neues Projekt erstellen, ViewController-Quelle ersetzen, MyView-Datei hinzufügen und es sollte wie auf meinem Computer funktionieren. – FredericP