Czy istnieje prosty sposób na umożliwienie interakcji z przyciskiem w UIView, który znajduje się pod innym UIView - gdzie nie ma żadnych rzeczywistych obiektów z górnego UIView na przycisku?
Na przykład w tej chwili mam UIView (A) z obiektem na górze i obiektem na dole ekranu i niczym na środku. Znajduje się on na innym UIView, który ma przyciski pośrodku (B). Jednak nie wydaje mi się, żebym wchodził w interakcję z przyciskami w środku B.
Widzę przyciski w B - ustawiłem tło A na clearColor - ale wydaje się, że przyciski w B nie są dotknięte, mimo że na górze tych przycisków nie ma żadnych obiektów z A.
EDYTUJ - nadal chcę mieć możliwość interakcji z obiektami w górnym UIView
Z pewnością jest na to prosty sposób?
objective-c
ios
cocoa-touch
delany
źródło
źródło
UIButton
która jest pod półprzezroczystą,UIView
podczas gdy nieprzezroczysta częśćUIView
będzie nadal reagować na zdarzenia dotykowe.Odpowiedzi:
Powinieneś utworzyć podklasę UIView dla swojego widoku z góry i zastąpić następującą metodę:
Możesz również spojrzeć na metodę hitTest: event:.
źródło
return
robi to stwierdzenie, alereturn CGRectContainsPoint(eachSubview.frame, point)
działa dla mnie. Niezwykle pomocna odpowiedź w przeciwnym razieMIDDLE_Y1<=y<=MIDDLE_Y2
okolicy.Chociaż wiele odpowiedzi tutaj zadziała, jestem trochę zaskoczony, widząc, że nie podano tutaj najwygodniejszej, ogólnej i niezawodnej odpowiedzi. @Ash był najbliżej, z tym wyjątkiem, że dzieje się coś dziwnego z powrotem superwizji ... nie rób tego.
Ta odpowiedź jest pobierana z odpowiedzi dałem podobnym pytaniem, tutaj .
[super hitTest:point withEvent:event]
zwróci najgłębszy widok w hierarchii tego widoku, który został dotknięty. JeślihitView == self
(tj. Jeśli pod punktem dotyku nie ma widoku podrzędnego), wróćnil
, określając, że ten widok nie powinien otrzymać dotknięcia. Sposób działania łańcucha odpowiedzi oznacza, że hierarchia widoków powyżej tego punktu będzie kontynuowana, dopóki nie zostanie znaleziony widok reagujący na dotyk. Nie zwracaj superwizji, ponieważ od tego poglądu nie zależy, czy jej superview powinien akceptować dotknięcia, czy nie!To rozwiązanie to:
pointInside:withEvent:
celu zwrócenia określonego obszaru do dotknięcia).Używam tego na tyle często, że wyabstrahowałem go do podklasy, aby zapisać podklasy bezcelowego widoku dla jednego zastąpienia. Jako bonus dodaj właściwość, aby była konfigurowalna:
Następnie zaszalej i użyj tego widoku, gdziekolwiek możesz użyć zwykłego
UIView
. Konfiguracja jest tak proste jak tworzenieonlyRespondToTouchesInSubviews
sięYES
.źródło
Możesz sobie z tym poradzić na kilka sposobów. Moim ulubionym jest przesłonięcie hitTest: withEvent: w widoku, który jest wspólnym superwizorem (może pośrednio) na sprzeczne widoki (brzmi to tak, jakbyś nazywał te A i B). Na przykład coś takiego (tutaj A i B to wskaźniki UIView, gdzie B to wskaźnik „ukryty”, który jest zwykle ignorowany):
Możesz także zmodyfikować
pointInside:withEvent:
metodę zgodnie z sugestią gyim. Pozwala to osiągnąć zasadniczo ten sam rezultat, skutecznie „wbijając dziurę” w A, przynajmniej za dotknięcia.Innym podejściem jest przekazywanie zdarzeń, co oznacza nadpisywanie
touchesBegan:withEvent:
i podobne metody (takie jaktouchesMoved:withEvent:
itp.) Do wysyłania niektórych dotknięć do innego obiektu niż ten, do którego trafiły po raz pierwszy. Na przykład w A możesz napisać coś takiego:Jednak nie zawsze będzie to działać tak, jak oczekujesz! Najważniejsze jest to, że wbudowane kontrolki, takie jak UIButton, zawsze ignorują przekazane dotknięcia. Z tego powodu pierwsze podejście jest bardziej niezawodne.
Jest dobry post na blogu wyjaśniający to wszystko bardziej szczegółowo, wraz z małym działającym projektem xcode do demonstracji pomysłów, dostępnym tutaj:
http://bynomial.com/blog/?p=74
źródło
Musisz ustawić
upperView.userInteractionEnabled = NO;
, w przeciwnym razie górny widok przechwyci dotknięcia.Wersja programu Interface Builder to pole wyboru u dołu panelu View Attributes o nazwie „User Interaction Enabled”. Odznacz to i powinieneś być gotowy.
źródło
Niestandardowa implementacja pointInside: withEvent: rzeczywiście wydawała się właściwą drogą, ale obsługa zakodowanych współrzędnych wydawała mi się dziwna. Skończyło się więc na sprawdzeniu, czy CGPoint znajduje się wewnątrz przycisku CGRect za pomocą funkcji CGRectContainsPoint ():
źródło
Ostatnio napisałem klasę, która pomoże mi właśnie w tym. Używanie go jako klasy niestandardowej dla
UIButton
lubUIView
spowoduje przekazanie zdarzeń dotykowych, które zostały wykonane na przezroczystym pikselu.To rozwiązanie jest nieco lepsze niż zaakceptowana odpowiedź, ponieważ nadal możesz kliknąć element
UIButton
znajdujący się pod półprzezroczystą,UIView
podczas gdy nieprzezroczysta częśćUIView
nadal będzie reagować na zdarzenia dotykowe.Jak widać na GIF-ie, przycisk Żyrafa jest prostym prostokątem, ale zdarzenia dotykowe na przezroczystych obszarach są przenoszone na żółty
UIButton
pod spodem.Link do zajęć
źródło
Chyba trochę się spóźniłem na tę imprezę, ale dodam to możliwe rozwiązanie:
Jeśli użyjesz tego kodu do zastąpienia standardowej funkcji hitTest niestandardowego UIView, zignoruje on TYLKO sam widok. Wszelkie podziały tego widoku będą normalnie zwracać trafienia, a wszelkie trafienia, które trafiłyby do samego widoku, są przekazywane do jego superwidoku.
-Popiół
źródło
[self superview]
. dokumentacja dotycząca tej metody zawiera stan „Zwraca najdalszego potomka odbiornika w hierarchii widoków (łącznie ze sobą), który zawiera określony punkt” oraz „Zwraca zero, jeśli punkt leży całkowicie poza hierarchią widoków odbiornika”. myślę, że powinieneś wrócićnil
. kiedy zwrócisz zero, kontrola przejdzie do superview, aby sprawdzić, czy ma jakieś trafienia, czy nie. więc zasadniczo zrobi to samo, z wyjątkiem tego, że powrót superwiewu może zepsuć coś w przyszłości.Po prostu riffowanie na Accepted Answer i umieszczanie tego tutaj w celach informacyjnych. Zaakceptowana odpowiedź działa doskonale. Możesz go rozszerzyć w ten sposób, aby umożliwić podglądom podrzędnym swojego widoku dotarcie lub przekazanie go do wszystkich widoków za nami:
Uwaga: nie musisz nawet wykonywać rekursji w drzewie podwidoku, ponieważ każda
pointInside:withEvent:
metoda zajmie się tym za Ciebie.źródło
Może pomóc ustawienie wyłączonej właściwości userInteraction. Na przykład:
(Uwaga: w powyższym kodzie „self” odnosi się do widoku)
W ten sposób możesz wyświetlać tylko w topView, ale nie będziesz otrzymywać danych wejściowych użytkownika. Wszystkie dotknięcia użytkownika przejdą przez ten widok, a dolny widok odpowie za nie. Użyłbym tego topView do wyświetlania przezroczystych obrazów lub ich animacji.
źródło
To podejście jest dość przejrzyste i pozwala, aby przezroczyste podglądy nie reagowały również na dotknięcia. Po prostu podklasę
UIView
i dodaj następującą metodę do jej implementacji:źródło
Moje rozwiązanie tutaj:
Mam nadzieję że to pomoże
źródło
Jest coś, co możesz zrobić, aby przechwycić dotyk w obu widokach.
Widok z góry:
Ale taki jest pomysł.
źródło
Oto wersja Swift:
źródło
Szybki 3
źródło
Nigdy nie zbudowałem pełnego interfejsu użytkownika przy użyciu zestawu narzędzi UI, więc nie mam z nim dużego doświadczenia. Oto, co moim zdaniem powinno działać.
Każdy UIView, a to UIWindow, ma właściwość
subviews
, która jest NSArray zawierającą wszystkie podwidoki.Pierwszy podgląd podrzędny dodany do widoku otrzyma indeks 0, a następny indeks 1 i tak dalej. Można również wymienić
addSubview:
zinsertSubview: atIndex:
lubinsertSubview:aboveSubview:
i takich metod, które może określić pozycję swojej podrzędny w hierarchii.Sprawdź więc swój kod, aby zobaczyć, który widok dodajesz jako pierwszy do swojego UIWindow. To będzie 0, a druga będzie 1.
Teraz, z jednego z podglądów podrzędnych, aby przejść do drugiego, wykonaj następujące czynności:
Daj mi znać, jeśli to zadziała w Twoim przypadku!
(pod tym znacznikiem jest moja poprzednia odpowiedź):
Jeśli widoki muszą się ze sobą komunikować, powinny to robić za pośrednictwem kontrolera (czyli przy użyciu popularnego modelu MVC ).
Tworząc nowy widok, możesz się upewnić, że zarejestruje się on w kontrolerze.
Technika polega więc na tym, aby upewnić się, że widoki są rejestrowane za pomocą kontrolera (który może przechowywać je według nazwy lub cokolwiek wolisz w słowniku lub tablicy). Albo możesz poprosić kontroler o wysłanie wiadomości dla ciebie, albo możesz uzyskać odniesienie do widoku i komunikować się z nim bezpośrednio.
Jeśli twój widok nie ma linku do kontrolera (co może mieć miejsce), możesz użyć singletonów i / lub metod klas, aby uzyskać odwołanie do kontrolera.
źródło
Myślę, że właściwym sposobem jest użycie łańcucha widoków wbudowanego w hierarchię widoków. W przypadku widoków podrzędnych, które są wypychane do widoku głównego, nie używaj ogólnego UIView, ale zamiast tego podklasy UIView (lub jednego z jego wariantów, takich jak UIImageView), aby utworzyć MYView: UIView (lub dowolny inny typ nadrzędny, taki jak UIImageView). W implementacji YourView zaimplementuj metodę touchesBegan. Ta metoda zostanie następnie wywołana po dotknięciu tego widoku. Wszystko, co musisz mieć w tej implementacji, to metoda instancji:
to dotykaBegan jest interfejsem odpowiadającym, więc nie musisz deklarować go w swoim publicznym ani prywatnym interfejsie; to jeden z tych magicznych interfejsów API, o których musisz tylko wiedzieć. Ten self.superview ostatecznie przesyła żądanie do elementu viewController. W kontrolerze viewController zaimplementuj to dotknięciaBegan do obsługi dotyku.
Zwróć uwagę, że lokalizacja dotknięć (CGPoint) jest automatycznie dostosowywana względem otaczającego widoku, gdy jest przesuwana w górę łańcucha hierarchii widoków.
źródło
Po prostu chcę to opublikować, bo miałem podobny problem, spędziłem dużo czasu próbując wdrożyć tutaj odpowiedzi bez powodzenia. Co ostatecznie zrobiłem:
i wdrażanie
UIGestureRecognizerDelegate
:Widok z dołu był kontrolerem nawigacyjnym z wieloma segmentami, a na górze miałem coś w rodzaju drzwi, które można było zamknąć gestem przesuwania. Całość została osadzona w kolejnym VC. Działał jak urok. Mam nadzieję że to pomoże.
źródło
Wdrożenie Swift 4 dla rozwiązania opartego na HitTest
źródło
Wywodzący się z doskonałej i przede wszystkim niezawodnej odpowiedzi Stuarta oraz użytecznej implementacji Segeva, oto pakiet Swift 4, który możesz wrzucić do dowolnego projektu:
A potem z hitTest:
źródło