Gegebene folgende Hierarchie:
%Vor%Aufgabe:
Die Kreuze von superview
und subview
müssen bei einer globalen Transformation immer ausgerichtet sein. Weitere Details im Abschnitt "Anforderungen".
Kontext:
Die obige Ansichtshierarchie gehört zu einem Diagramm. Um maximale Flexibilität zu bieten, erlaubt es, Chartpunkte & amp; verwandte Inhalte auf 3 verschiedene Arten:
Zeichnen in der Basisansicht des Diagramms ( superview
) draw
method.
Hinzufügen von Unteransichten zu subview
. subview
wird auf Zoom / Pan und damit automatisch auf seine Subviews transformiert.
Hinzufügen von Untersichten zu einem gleichgeordneten Element von subview
. Aus Gründen der Einfachheit nicht in der Ansichtshierarchie dargestellt und weil es nicht mit dem Problem verbunden ist. Erwähnen Sie es hier nur, um einen Überblick zu geben. Der Unterschied zwischen dieser Methode und 2. besteht darin, dass hier die Ansicht nicht transformiert wird, so dass es der Implementierung des Inhalts überlassen wird, die Transformation aller untergeordneten Elemente "manuell" zu aktualisieren.
Maximale Flexibilität! Aber dadurch entstehen die Kosten, die es ein bisschen schwierig zu implementieren ist. Insbesondere Punkt 2.
Gegenwärtig arbeite ich mit Zoom / Pan, indem ich die Transformationen für superview
core graphics drawing und subview
getrennt verarbeite, aber dies führt zu Redundanz und Fehleranfälligkeit, z. wiederholter Code für Grenzkontrollen usw.
Nun versuche ich es zu refaktorisieren, um eine globale Matrix zu verwenden, um alle Transformationen zu speichern und daraus alles abzuleiten. Das Anwenden der globalen Matrix auf die Koordinaten, die von superview
zum Zeichnen verwendet werden, ist trivial, aber das Ableiten der Matrix von subview
, unter Berücksichtigung der Anforderungen, die im nächsten Abschnitt aufgeführt sind, nicht so sehr.
Ich erwähne "Kreuze" in der Ansichtshierarchie, weil ich das auf meinen Spielplätzen als vereinfachte Darstellung eines Diagrammpunkts (mit x / y-Richtlinien) verwende (Sie können nach Bildern und Aufrissen nach unten blättern).
Anforderungen:
subview
's Unteransichten, d. h. die Kreuzlinienansichten können nicht berührt werden (z. B. um Transformationen auf sie anzuwenden) - alles, was modifiziert werden kann, ist subview
' s transform. matrix
. matrix
werden dann die Koordinaten des gezeichneten Kreuzes in superview
(trivial), sowie die Transformationsmatrix von subview
(nicht trivial - Grund dieser Frage) berechnet.
subview
eindeutig von der globalen Matrix abzuleiten, ist es erlaubt, zusätzliche Daten in Variablen zu speichern, die dann zusammen mit der globalen Matrix verwendet werden, um subview
'zu berechnen. s Matrix. container
kann sich beim Zoomen / Schwenken ändern. Der Grund dafür ist, dass die Beschriftungen der Y-Achse unterschiedliche Längen haben können und dass die Tabelle die Inhaltsgröße dynamisch an den von den Beschriftungen belegten Platz anpassen muss (während des Zoomens und Schwenkens). container
ändert, muss natürlich das Verhältnis der Bildschirmkoordinaten der Domäne entsprechend geändert werden, sodass die vollständige ursprüngliche sichtbare Domäne weiterhin in container
enthalten ist. ZB wenn ich eine x-Achse mit einer Domain [0, 10] in einem Container-Frame mit einer Breite von 500pt anzeigen würde, dh das Verhältnis zum Konvertieren eines Domain-Punktes zu Bildschirmkoordinaten ist 500/10=50
und verkleinern die Containerbreite auf 250, jetzt meine Domain [0, 10], die in diese neue Breite passen muss, hat ein Verhältnis von 25. Was ich getan habe:
Hier sind Schritt-für-Schritt-Spielplätze, die ich gemacht habe, um das Problem besser zu verstehen:
Schritt 1 (funktioniert):
Erstellen Sie die Hierarchie, wie am Anfang beschrieben, und zeigen Sie nur Kreuze an, die während des (programmatischen) Zooms & amp; Pfanne. Erfüllt die Anforderungen 1, 2, 3, 4 und 5:
Besonderheiten hier:
container
view übersprungen, um es einfach zu halten. subview
ist eine direkte Unteransicht von superview
. subview
hat die gleiche Größe wie superview
(vor dem Zoomen natürlich), um es auch einfach zu halten. subview
auf den Ursprung (0, 0), was notwendig ist, um mit der globalen Matrix synchron zu sein. subviewAnchorTranslation
. Dies gehört zu den zusätzlichen Daten, die ich im Bullet unter Anforderung 5 im Hinterkopf hatte.Ok, wie du siehst, funktioniert hier alles. Zeit, um den nächsten Schritt zu versuchen.
Schritt 2 (funktioniert):
Eine Kopie von Schritt 1 Spielplatz mit Modifikationen:
container
view hinzugefügt, ähnelt nun der zu Beginn beschriebenen Ansichtshierarchie. subview
, das nun eine Unteransicht von container
ist, weiterhin an der gleichen Position angezeigt wird, muss es um -container.origin
. Die Kreuze sind weiterhin synchron. Anforderungen erfüllt: Alle von Schritt 1 + Anforderung 6. Gist mit Spielplatz
Schritt 3 (funktioniert nicht):
Bisher habe ich mit einem Bildschirmbereich gearbeitet, der bei 0 beginnt (linke Seite des sichtbaren Spielplatzergebnisses). Dies bedeutet, dass container
nicht die Funktion erfüllt, den Bereich zu enthalten, d. H. Anforderung 7. Um dies zu erfüllen, muss der Ursprung von container
in die Verhältnisberechnung einbezogen werden.
Jetzt muss auch subview
skaliert werden um in container
zu passen / das Kreuz an der richtigen Stelle anzuzeigen. Das fügt eine zweite Variable hinzu (zuerst subviewAnchorTranslation
), die ich contentScalingFactor
genannt habe und die diese Skalierung enthält, die in die Matrixberechnung von subview
einbezogen werden muss.
Hier habe ich mehrere Experimente gemacht, die alle fehlgeschlagen sind. Im aktuellen Status beginnt subview
mit demselben Frame wie container
und sein Frame wird angepasst + skaliert, wenn sich der Frame von container
ändert. Auch wenn subview
jetzt innerhalb des Containers ist, dh sein Ursprung ist nun container
's Ursprung und nicht superview
' s Ursprung, ich muss seinen Anker so updaten, dass der Ursprung nicht bei (0,0) ist (-x, -y), wobei x und y die Koordinaten des Ursprungs von container
sind, so dass subview
weiterhin in Bezug auf den Ursprung von superview
liegt. Und es erscheint logisch, diesen Anker jedes Mal zu aktualisieren, wenn container
seinen Ursprung ändert, da dies die relative Position vom Ursprung von content
zum Ursprung von superview
ändert.
Ich habe Code dafür hochgeladen - in diesem Fall ein komplettes iOS-Projekt statt nur eines Spielplatzes (ich dachte anfangs, dass es funktionierte und wollte mit tatsächlichen Gesten testen). In dem eigentlichen Projekt arbeite ich an der Transformation funktioniert besser, aber ich konnte den Unterschied nicht finden. Jedenfalls funktioniert es nicht gut, irgendwann gibt es immer kleine Offsets und die Punkte / Kreuze geraten aus dem Takt.
Ok, wie löse ich das so, dass alle Bedingungen erfüllt sind. Die Kreuze müssen synchron bleiben, mit kontinuierlichem Zoomen / Schwenken und Ändern des Rahmens von container
dazwischen.
Die vorliegende Antwort erlaubt es, jede Ansicht in der Child-Hierarchie beliebig zu transformieren. nicht verfolgt die Transformation, konvertiert lediglich einen transformierten Punkt und beantwortet somit die Frage:
Was sind die Koordinaten eines Punktes, der sich in einer Unteransicht im Koordinatensystem einer anderen Ansicht befindet, unabhängig davon, wie stark diese Unteransicht umgewandelt wurde .
Um das Parent vom Clipping Container zu entkoppeln und eine generische Antwort anzubieten, schlage ich vor, sie auf der gleichen Ebene konzeptionell und in zu platzieren andere Reihenfolge visuell (†) :
Um das Scrollen, Zoomen oder eine andere Transformation von Kind auf Eltern anzuwenden, gehen Sie durch die gemeinsame Superansicht ( Koordinator in der Beispiel).
Der Ansatz ist der Stapelüberlauf-Antwort sehr ähnlich, wo zwei UIScrollView
mit unterschiedlicher Geschwindigkeit scrollen.
Beachten Sie, dass die rote und schwarze Haarlinie sich unabhängig von der Position überlappen, die einzelnen Ansichten in der Hierarchie Child
transformieren, einschließlich der von Container
.
Koordinatenumrechnung
Vereinfachte Darstellung durch Verwendung eines beliebigen Punktes (50,50) im Koordinatensystem der Ansicht Child (wo dieser Punkt effektiv gezeichnet wird) und Konvertierung in Parent View-System sieht folgendermaßen aus:
%Vor%Zoom & amp; Container übersetzen
%Vor%(†) Ich habe Superview und Unteransicht in Parent und Child umbenannt.