Gibt es eine einfache Möglichkeit, die Interaktion mit einer Schaltfläche in einer UIView zuzulassen, die sich unter einer anderen UIView befindet - wo sich keine tatsächlichen Objekte aus der oberen UIView über der Schaltfläche befinden?
Zum Beispiel habe ich im Moment eine UIView (A) mit einem Objekt oben und einem Objekt unten auf dem Bildschirm und nichts in der Mitte. Diese befindet sich auf einer anderen UIView mit Schaltflächen in der Mitte (B). Ich kann jedoch nicht mit den Schaltflächen in der Mitte von B interagieren.
Ich kann die Schaltflächen in B sehen - ich habe den Hintergrund von A auf clearColor gesetzt -, aber die Schaltflächen in B scheinen keine Berührungen zu erhalten, obwohl sich keine Objekte von A tatsächlich über diesen Schaltflächen befinden.
BEARBEITEN - Ich möchte weiterhin in der Lage sein, mit den Objekten in der oberen UIView zu interagieren
Sicher gibt es einen einfachen Weg, dies zu tun?
quelle
UIButton
, die sich unter einer halbtransparenten befindet,UIView
während der nicht transparente Teil derUIView
weiterhin auf Berührungsereignisse reagiert.Antworten:
Sie sollten eine UIView-Unterklasse für Ihre Draufsicht erstellen und die folgende Methode überschreiben:
Sie können sich auch die Methode hitTest: event: ansehen.
quelle
return
Aussage tut, aber siereturn CGRectContainsPoint(eachSubview.frame, point)
funktioniert für mich.MIDDLE_Y1<=y<=MIDDLE_Y2
Umgebung "transparent" .Obwohl viele der Antworten hier funktionieren werden, bin ich ein wenig überrascht zu sehen, dass die bequemste, allgemeinste und narrensicherste Antwort hier nicht gegeben wurde. @Ash kam am nächsten, außer dass mit der Rückgabe der Übersicht etwas Seltsames los ist ... tu das nicht.
Diese Antwort stammt aus einer Antwort, die ich hier auf eine ähnliche Frage gegeben habe .
[super hitTest:point withEvent:event]
gibt die tiefste Ansicht in der Hierarchie dieser Ansicht zurück, die berührt wurde. WennhitView == self
(dh wenn sich unter dem Berührungspunkt keine Unteransicht befindet), kehren Sie zurücknil
und geben an, dass diese Ansicht die Berührung nicht erhalten soll. Die Funktionsweise der Responderkette bedeutet, dass die Ansichtshierarchie über diesem Punkt weiterhin durchlaufen wird, bis eine Ansicht gefunden wird, die auf die Berührung reagiert. Geben Sie die Übersicht nicht zurück, da es dieser Ansicht nicht überlassen ist, ob die Übersicht Berührungen akzeptieren soll oder nicht!Diese Lösung ist:
pointInside:withEvent:
, um einen bestimmten berührbaren Bereich zurückzugeben).Ich verwende dies oft genug, um es in eine Unterklasse zu abstrahieren, um sinnlose Ansichtsunterklassen für eine Überschreibung zu speichern. Fügen Sie als Bonus eine Eigenschaft hinzu, um sie konfigurierbar zu machen:
Dann gehen Sie wild und verwenden Sie diese Ansicht, wo immer Sie eine Ebene verwenden könnten
UIView
. Die Konfiguration ist so einfach wie das EinstellenonlyRespondToTouchesInSubviews
aufYES
.quelle
Es gibt verschiedene Möglichkeiten, wie Sie damit umgehen können. Mein Favorit ist es, hitTest: withEvent: in einer Ansicht zu überschreiben, die eine gemeinsame Übersicht (möglicherweise indirekt) zu den widersprüchlichen Ansichten darstellt (klingt so, als würden Sie diese A und B nennen). Zum Beispiel so etwas (hier sind A und B UIView-Zeiger, wobei B der "versteckte" ist, der normalerweise ignoriert wird):
Sie können die
pointInside:withEvent:
Methode auch wie von Gyim vorgeschlagen ändern. Auf diese Weise können Sie im Wesentlichen das gleiche Ergebnis erzielen, indem Sie zumindest bei Berührungen effektiv ein Loch in A "stechen".Ein anderer Ansatz ist die Ereignisweiterleitung, dh das Überschreiben
touchesBegan:withEvent:
und ähnliche Methoden (wietouchesMoved:withEvent:
usw.), um einige Berührungen an ein anderes Objekt zu senden, als wenn sie zuerst ausgeführt werden. In A könnten Sie beispielsweise Folgendes schreiben:Dies funktioniert jedoch nicht immer so, wie Sie es erwarten! Die Hauptsache ist, dass eingebaute Steuerelemente wie UIButton weitergeleitete Berührungen immer ignorieren. Aus diesem Grund ist der erste Ansatz zuverlässiger.
Es gibt einen guten Blog-Beitrag, der dies alles ausführlicher erklärt, zusammen mit einem kleinen funktionierenden Xcode-Projekt, um die Ideen zu demonstrieren, das hier verfügbar ist:
http://bynomial.com/blog/?p=74
quelle
Sie müssen einstellen
upperView.userInteractionEnabled = NO;
, sonst fängt die obere Ansicht die Berührungen ab.Die Interface Builder-Version ist ein Kontrollkästchen am unteren Rand des Bedienfelds "Ansichtsattribute" mit dem Namen "Benutzerinteraktion aktiviert". Deaktivieren Sie es und Sie sollten bereit sein zu gehen.
quelle
Benutzerdefinierte Implementierung von pointInside: withEvent: schien zwar der richtige Weg zu sein, aber der Umgang mit fest codierten Koordinaten erschien mir seltsam. Also habe ich mit der Funktion CGRectContainsPoint () überprüft, ob sich der CGPoint in der Schaltfläche CGRect befindet:
quelle
In letzter Zeit habe ich eine Klasse geschrieben, die mir dabei helfen wird. Wenn Sie es als benutzerdefinierte Klasse für ein
UIButton
oderUIView
mehrere Berührungsereignisse verwenden, die auf einem transparenten Pixel ausgeführt wurden.Diese Lösung ist etwas besser als die akzeptierte Antwort, da Sie immer noch auf eine Antwort klicken können
UIButton
, die sich unter einer halbtransparenten befindet,UIView
während der nicht transparente Teil der LösungUIView
weiterhin auf Berührungsereignisse reagiert.Wie Sie im GIF sehen können, ist die Giraffenschaltfläche ein einfaches Rechteck, aber Berührungsereignisse in transparenten Bereichen werden an das
UIButton
darunter liegende Gelb weitergeleitet .Link zur Klasse
quelle
Ich glaube, ich bin etwas spät dran, aber ich werde diese mögliche Lösung hinzufügen:
Wenn Sie diesen Code verwenden, um die Standard-HitTest-Funktion eines benutzerdefinierten UIView zu überschreiben, wird NUR die Ansicht selbst ignoriert. Alle Unteransichten dieser Ansicht geben ihre Treffer normal zurück, und alle Treffer, die in die Ansicht selbst gelangt wären, werden an ihre Übersicht weitergeleitet.
-Asche
quelle
[self superview]
. In der Dokumentation zu dieser Methode heißt es: "Gibt den am weitesten entfernten Nachkommen des Empfängers in der Ansichtshierarchie (einschließlich sich selbst) zurück, der einen bestimmten Punkt enthält" und "Gibt null zurück, wenn der Punkt vollständig außerhalb der Ansichtshierarchie des Empfängers liegt". Ich denke, Sie sollten zurückkehrennil
. Wenn Sie nil zurückgeben, wird die Steuerung an die Übersicht übergeben, um zu überprüfen, ob Treffer vorhanden sind oder nicht. Im Grunde wird es das Gleiche tun, außer dass die Rückkehr der Übersicht in Zukunft etwas kaputt machen könnte.Ich habe nur die akzeptierte Antwort durchgesehen und sie hier als Referenz eingefügt. Die akzeptierte Antwort funktioniert einwandfrei. Sie können es folgendermaßen erweitern, damit die Unteransichten Ihrer Ansicht die Berührung erhalten, ODER es an alle Ansichten hinter uns weitergeben:
Hinweis: Sie müssen nicht einmal eine Rekursion für den Unteransichtsbaum durchführen, da jede
pointInside:withEvent:
Methode dies für Sie erledigt .quelle
Das Deaktivieren der Eigenschaft userInteraction kann hilfreich sein. Z.B:
(Hinweis: Im obigen Code bezieht sich 'self' auf eine Ansicht.)
Auf diese Weise können Sie nur in der topView anzeigen, erhalten jedoch keine Benutzereingaben. Alle diese Benutzerberührungen werden durch diese Ansicht und die Unteransicht wird für sie antworten. Ich würde diese topView verwenden, um transparente Bilder anzuzeigen oder sie zu animieren.
quelle
Dieser Ansatz ist recht sauber und ermöglicht, dass transparente Unteransichten nicht auch auf Berührungen reagieren. Unterklasse einfach
UIView
und füge der Implementierung die folgende Methode hinzu:quelle
Meine Lösung hier:
Hoffe das hilft
quelle
In beiden Ansichten können Sie die Berührung abfangen.
Draufsicht:
Aber das ist die Idee.
quelle
Hier ist eine Swift-Version:
quelle
Swift 3
quelle
Ich habe noch nie eine vollständige Benutzeroberfläche mit dem UI-Toolkit erstellt, daher habe ich nicht viel Erfahrung damit. Hier ist, was ich denke, sollte funktionieren.
Jedes UIView und das UIWindow hat eine Eigenschaft
subviews
, bei der es sich um ein NSArray handelt, das alle Unteransichten enthält.Die erste Unteransicht, die Sie einer Ansicht hinzufügen, erhält den Index 0 und den nächsten Index 1 usw. Sie können auch ersetzen
addSubview:
mitinsertSubview: atIndex:
oderinsertSubview:aboveSubview:
und solche Methoden , die die Position Ihrer Subview in der Hierarchie bestimmen kann.Überprüfen Sie also Ihren Code, um festzustellen, welche Ansicht Sie zuerst zu Ihrem UIWindow hinzufügen. Das ist 0, das andere ist 1.
Nun würden Sie in einer Ihrer Unteransichten Folgendes tun, um eine andere zu erreichen:
Lassen Sie mich wissen, ob das für Ihren Fall funktioniert!
(Unter diesem Marker befindet sich meine vorherige Antwort):
Wenn Ansichten miteinander kommunizieren müssen, sollten sie dies über einen Controller tun ( dh mithilfe der beliebten MVC) Modells).
Wenn Sie eine neue Ansicht erstellen, können Sie sicherstellen, dass sie sich bei einem Controller registriert.
Die Technik besteht also darin, sicherzustellen, dass sich Ihre Ansichten bei einem Controller registrieren (der sie nach Namen oder nach Belieben in einem Wörterbuch oder Array speichern kann). Entweder kann der Controller eine Nachricht für Sie senden, oder Sie können einen Verweis auf die Ansicht abrufen und direkt mit ihr kommunizieren.
Wenn Ihre Ansicht keinen Link zum Controller enthält (was möglicherweise der Fall ist), können Sie Singletons und / oder Klassenmethoden verwenden, um einen Verweis auf Ihren Controller zu erhalten.
quelle
Ich denke, der richtige Weg ist, die in die Ansichtshierarchie integrierte Ansichtskette zu verwenden. Verwenden Sie für Ihre Unteransichten, die in die Hauptansicht verschoben werden, nicht die generische UIView, sondern die Unterklasse UIView (oder eine ihrer Varianten wie UIImageView), um MYView: UIView (oder einen beliebigen Supertyp wie UIImageView) zu erstellen. Implementieren Sie in der Implementierung für YourView die touchBegan-Methode. Diese Methode wird dann aufgerufen, wenn diese Ansicht berührt wird. Alles, was Sie in dieser Implementierung benötigen, ist eine Instanzmethode:
Diese BerührungBegan ist eine Responder-API, sodass Sie sie nicht in Ihrer öffentlichen oder privaten Benutzeroberfläche deklarieren müssen. Es ist eine dieser magischen APIs, über die Sie nur Bescheid wissen müssen. Diese self.superview sprudelt die Anfrage schließlich an den viewController. Implementieren Sie dann im viewController diesen touchBegan, um die Berührung zu verarbeiten.
Beachten Sie, dass die Berührungsposition (CGPoint) automatisch relativ zur umfassenden Ansicht für Sie angepasst wird, wenn sie in der Ansichtshierarchiekette zurückgeworfen wird.
quelle
Ich möchte dies nur posten, da ich ein ähnliches Problem hatte und viel Zeit damit verbracht habe, Antworten hier ohne Glück umzusetzen. Was ich letztendlich gemacht habe:
und Umsetzung
UIGestureRecognizerDelegate
:Die Ansicht von unten war ein Navigationscontroller mit einer Anzahl von Abschnitten, und ich hatte eine Art Tür darüber, die sich mit einer Schwenkgeste schließen konnte. Das Ganze war in eine weitere VC eingebettet. Lief wie am Schnürchen. Hoffe das hilft.
quelle
Swift 4-Implementierung für HitTest-basierte Lösung
quelle
Abgeleitet von Stuarts hervorragender und größtenteils narrensicherer Antwort und Segevs nützlicher Implementierung ist hier ein Swift 4-Paket, das Sie in jedes Projekt einbinden können:
Und dann mit hitTest:
quelle