Jak przekazać zdarzenie onClick widoku do jego elementu nadrzędnego w systemie Android?

100

Mam TextView w układzie, którego tło jest selektorem. Tekst TextView jest ustawiony na Spanned from HTML. Następnie ustawiam TextView za pomocą LinkMovementMethod.

Teraz, gdy stukam w TextView, zdarzenie kliknięcia nie jest wysyłane do jego układu nadrzędnego w celu wyzwolenia selektora.

Jak to rozwiązać?

shiami
źródło

Odpowiedzi:

45

Myślę, że musisz użyć jednej z tych metod, aby móc przechwycić zdarzenie, zanim zostanie wysłane do odpowiednich komponentów:

Activity.dispatchTouchEvent(MotionEvent) - Dzięki temu Twoja aktywność może przechwytywać wszystkie zdarzenia dotykowe przed wysłaniem ich do okna.

ViewGroup.onInterceptTouchEvent(MotionEvent) - Dzięki temu ViewGroup może obserwować zdarzenia, gdy są one wysyłane do podrzędnych widoków.

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Wywołaj to w widoku nadrzędnym, aby wskazać, że nie powinien przechwytywać zdarzeń dotykowych za pomocą onInterceptTouchEvent (MotionEvent).

Więcej informacji tutaj .

Mam nadzieję, że to pomoże.

Luis Miguel Serrano
źródło
1
Czy istnieje łatwiejszy sposób przekazywania zdarzeń w celu wywołania onClick i onLongClick w widoku nadrzędnym, czy też muszę je zaimplementować samodzielnie?
shiami,
Sprawdź to: stackoverflow.com/questions/2136696/pass-event-to-parent-view Być może będziesz chciał spróbować przekazać ten sam odbiornik kliknięć do innych instancji, jak sugerowano, nawet jeśli nie wiem, czy to zadziała , ale warto spróbować.
Luis Miguel Serrano,
Odpowiedź poniżej jest znacznie czystsza
JPM,
Czy powinienem utworzyć instancję MotionEvent? Proszę, wyjaśnij, @LuisMiguelSerrano
olegario
@olegario, zwykle przedefiniowujesz metodę, na przykład dla dispatchTouchEvent, za pomocą @Override, aby zdefiniować nowe zachowanie dla niej, więc po prostu otrzymujesz zdarzenie ruchu, które system dostarczył do Twojej aktywności (lub innego składnika aplikacji), a Ty traktować go i / lub przekazywać do dowolnej liczby komponentów podrzędnych zgodnie z własnymi zasadami. Coś jak: @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... }
Luis Miguel Serrano
212

Zadeklaruj, że TextViewnie możesz kliknąć / ustawić fokusu, używając android:clickable="false"i android:focusable="false"lub v.setClickable(false)i v.setFocusable(false). Zdarzenia kliknięcia powinny teraz zostać wysłane do TextViewrodzica użytkownika.

Uwaga:

Aby to osiągnąć , musisz dodać kliknięcie do jego bezpośredniego parent. lub set android:clickable="false"i android:focusable="false"do swojego bezpośredniego rodzica, aby przekazać słuchacz do kolejnego rodzica .

siyb
źródło
1
O rany, gdybym mógł dać to +100, zrobiłbym to. Próbowałem dowiedzieć się, jak sprawić, by kliknięcie działało tylko w ViewPager, a nie w układzie adapterów z TouchImageView implementującym onTouch! To rozwiązanie zadziałało jak urok.
JPM
1
ale co, jeśli chcę obsłużyć zdarzenie zmiany ostrości w EditText?
SweetWisher ツ
2
Scenariusz jest następujący: Mam układ, który zawiera edittext, układ względny, spinner i widok listy. Chcę odpalić zdarzenie dotykowe układu nadrzędnego za każdym razem, gdy dotykam dowolnego miejsca na ekranie, z wyjątkiem edytora i pokrętła
SweetWisher ツ
9
Coś ważne, aby pamiętać, że jeśli używasz TextView#setOnClickListener()na TextView, staje się interaktywna, nawet jeśli jest to uznane za android:clickable="false", a nawet jeśli The ClickListenerjest ustawiony na null( setOnclickListener(null))
Christian Garcia
3
Ciekawostka: jeśli w TextView znajduje się android:inputTypeatrybut, będzie on dyskretnie konsumował zdarzenia kliknięcia, nawet w przypadku klikalności: false & focusable: false; w moim przypadku było to stylowe i zajęło mi 30 minut, aby znaleźć przyczynę.
Kirill Karmazin
18

Czasami tylko to pomaga:

View child = parent.findViewById(R.id.btnMoreText);
    child.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            View parent = (View) v.getParent();
            parent.performClick();
        }
    });

Inny wariant, nie zawsze działa:

child.setOnClickListener(null);
Aleksandra Uchowa
źródło
To zadziałało CardViewjak dziecko, ponieważ CardViewwydaje się ignorować clickable="false"i focusable="false". Jednak używanie setOnTouchListeneri wywoływanie onTouchEventrodzica zamiast tego umożliwia rodzicowi wyświetlanie informacji zwrotnych na dotyk (np. Efekt tętnienia).
Methodsignature
Poniżej zamieściłem odpowiedni kod: stackoverflow.com/a/52928884/5652513 .
methodignature
10

Położyć

android:duplicateParentState="true"

u dziecka wtedy widoki uzyskują swój ciągliwy stan (skupiony, wciśnięty itp.) od swojego bezpośredniego rodzica, a nie od siebie samego. możesz ustawić onclick dla rodzica i wywołanie kliknięcia dziecka

Ahmad Ronagh
źródło
OP chce zadzwonić do słuchacza kliknięć rodzica, gdy zostanie kliknięte dziecko, a nie na odwrót.
Farid
3

Jeśli masz TextViewproblemy z kliknięciem, usuń android:inputType=""z pliku xml.

Sanjay Chaudhary
źródło
Jeśli nie wiesz dlaczego, radzę tego nie robić. Tylko mówię ... do każdego swojego.
dell116,
Powinieneś ustawić go naandroid:inputType="none"
AZ_
1

Ta odpowiedź jest podobna do odpowiedzi Aleksandra Ukhova , z tym wyjątkiem, że wykorzystuje zdarzenia dotykowe, a nie zdarzenia kliknięcia. Te zdarzenia pozwalają rodzicowi wyświetlać odpowiednie stany wciśnięcia (np. Efekt tętnienia). Ta odpowiedź jest również w Kotlinie zamiast w Javie.

view.setOnTouchListener { view, motionEvent ->
    (view.parent as View).onTouchEvent(motionEvent)
}
metody podpisu
źródło
0

Jeśli chcesz, aby oba OnTouchi OnClicksłuchacza do rodzicem a dzieckiem widzenia zarówno proszę skorzystać z poniższego trick:

  1. User ScrollView jako widok nadrzędny i wewnątrz, który umieścił widok podrzędny w Relative / LinearLayout.

  2. Ustaw Parent ScrollView, android:fillViewport="true"aby widok nie był przewijany.

  3. Następnie ustaw OnTouchodbiornik na rodzica, a OnClickodbiornik na widoki podrzędne. I ciesz się połączeniami zwrotnymi dla obu słuchaczy.

Kishor Patil
źródło