Chociaż większość dokumentów Apple jest bardzo dobrze napisana, myślę, że „ Przewodnik obsługi zdarzeń na iOS ” jest wyjątkiem. Trudno mi dokładnie zrozumieć, co zostało tam opisane.
Dokument mówi:
W testowaniu trafień okno wywołuje
hitTest:withEvent:
najwyższy widok hierarchii widoków; ta metoda jestpointInside:withEvent:
kontynuowana przez rekurencyjne wywoływanie każdego widoku w hierarchii widoków, który zwraca YES, przechodzenie w dół hierarchii, aż znajdzie podwidok, w którego granicach nastąpiło dotknięcie. Ten widok staje się widokiem testu trafień.
Czy jest więc tak, że tylko hitTest:withEvent:
najwyższy widok jest wywoływany przez system, który wywołuje pointInside:withEvent:
wszystkie widoki podrzędne, a jeśli wynik z określonego widoku podrzędnego jest TAK, to wywołania pointInside:withEvent:
podklas tego widoku podrzędnego?
Odpowiedzi:
Wydaje się to dość podstawowe pytanie. Ale zgadzam się z tobą, dokument nie jest tak jasny jak inne dokumenty, więc oto moja odpowiedź.
Wdrożenie
hitTest:withEvent:
w UIResponder polega na:pointInside:withEvent:
oself
hitTest:withEvent:
zwracanil
. koniec opowiadania.hitTest:withEvent:
wiadomości do swoich podglądów podrzędnych. zaczyna się od widoku podrzędnego najwyższego poziomu i kontynuuje do innych widoków, aż widok podrzędny zwróci element niebędącynil
obiektem lub wszystkie podglądy podrzędne otrzymają wiadomość.nil
obiekt niebędący obiektem po raz pierwszy, pierwszyhitTest:withEvent:
zwraca ten obiekt. koniec opowiadania.nil
obiektu niebędącego przedmiotem, pierwszyhitTest:withEvent:
zwracaself
Ten proces powtarza się rekurencyjnie, więc zwykle w końcu zwracany jest widok liścia hierarchii widoków.
Możesz jednak zastąpić,
hitTest:withEvent
aby zrobić coś inaczej. W wielu przypadkach nadpisywaniepointInside:withEvent:
jest prostsze i nadal zapewnia wystarczającą liczbę opcji, aby dostosować obsługę zdarzeń w aplikacji.źródło
hitTest:withEvent:
że wszystkie podglądy są w końcu wykonywane?hitTest:withEvent:
w swoich widokach (ipointInside
jeśli chcesz), wydrukuj dziennik i zadzwoń,[super hitTest...
aby dowiedzieć się, ktohitTest:withEvent:
jest wywoływany, w jakiej kolejności.Myślę, że mylisz podklasy z hierarchią widoków. To, co mówi doktor, jest następujące. Powiedzmy, że masz taką hierarchię widoków. Według hierarchii Nie mówię o hierarchii klas, ale o widokach w hierarchii widoków, jak następuje:
Powiedz, że włożyłeś palec do środka
D
. Oto, co się stanie:hitTest:withEvent:
jest wywoływanyA
, najwyższy widok hierarchii widoków.pointInside:withEvent:
jest wywoływana rekurencyjnie w każdym widoku.pointInside:withEvent:
jest wezwanyA
i wracaYES
pointInside:withEvent:
jest wezwanyB
i wracaNO
pointInside:withEvent:
jest wezwanyC
i wracaYES
pointInside:withEvent:
jest wezwanyD
i wracaYES
YES
, spogląda w dół na hierarchię, aby zobaczyć widok podrzędny, w którym miało miejsce dotknięcie. W tym przypadku, zA
,C
aD
, to będzieD
.D
będzie widokiem testu trafieńźródło
hitTest:withEvent:
B, C i D są również przywoływane. Co się stanie, jeśli D jest podziałem na C, a nie A? Chyba sięA
wróciłbyYES
również, tak jakC
iD
robi?Uważam, że to testowanie trafień w iOS jest bardzo pomocne
Edytuj Swift 4:
źródło
Dzięki za odpowiedzi, pomogli mi rozwiązać sytuację z widokami „nakładkowymi”.
Załóżmy
X
- dotyk użytkownika.pointInside:withEvent:
naB
zwrotachNO
, więchitTest:withEvent:
zwracaA
. Napisałem kategorię,UIView
aby poradzić sobie z problemem, gdy potrzebujesz dotknąć najbardziej widocznego widoku z góry.userInteractionEnabled
ustawieniem naNO
;self
,self
zostanie uznany za potencjalny wynik.Uwaga,
[self.subviewsreverseObjectEnumerator]
konieczne jest przestrzeganie hierarchii widoków od góry do dołu. I sprawdź, czyclipsToBounds
nie testujesz zamaskowanych podglądów podrzędnych.Stosowanie:
hitTest:withEvent:
toOficjalny przewodnik Apple zawiera również dobre ilustracje.
Mam nadzieję, że to komuś pomoże.
źródło
Pokazuje jak ten fragment!
źródło
Fragment @lion działa jak urok. Przeniosłem go do Swift 2.1 i użyłem jako rozszerzenia do UIView. Wysyłam to tutaj na wypadek, gdyby ktoś tego potrzebował.
Aby go użyć, po prostu zastąp hitTest: point: withEvent w swoim uiview w następujący sposób:
źródło
Diagram klas
Testowanie trafień
Znajdź
First Responder
First Responder
w tym przypadku jest to najgłębszaUIView
point()
metoda, która zwróciła prawdęhitTest()
Wygląda jak wewnątrzWyślij zdarzenie dotykowe do
First Responder
Spójrzmy na przykład
Łańcuch odpowiedzi
Spójrz na przykład
[Android onTouch]
źródło