Jakie jest znaczenie wartości logicznej zwracanej przez metodę obsługi zdarzeń w systemie Android

110

W systemie Android większość metod detektora zdarzeń zwraca wartość logiczną. Co oznacza ta wartość prawda / fałsz? co to przyniesie następstwom wydarzeń?

class MyTouchListener implements OnTouchListener {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        logView.showEvent(event);
        return true;
    }
}

Jeśli chodzi o powyższy przykład, jeśli zwrócono wartość true w metodzie onTouch , stwierdziłem, że każde zdarzenie dotykowe (DOWN, UP, MOVE itp.) Zostało przechwycone zgodnie z moim logView . Wręcz przeciwnie, jeśli wynik jest fałszywy, przechwycono tylko zdarzenie DOWN. Wydaje się więc, że zwrot false zapobiegnie propagacji zdarzenia. Mam rację ?

Ponadto w OnGestureListener wiele metod również musi zwracać wartość logiczną. Czy mają to samo znaczenie?

John Wang
źródło

Odpowiedzi:

140

Jeśli wrócisz truez ACTION_DOWNwydarzenia, będziesz zainteresowany pozostałymi wydarzeniami w tym geście. „Gest” w tym przypadku oznacza wszystkie wydarzenia do finału ACTION_UPlub ACTION_CANCEL. Wracając falseze ACTION_DOWNśrodka, którego nie chcesz, aby wydarzenie i inne widoki będą miały okazję się nim zająć. Jeśli masz nakładające się widoki, może to być widok dla rodzeństwa. Jeśli nie, to dotrze do rodzica.

adamp
źródło
3
adamp, czy istnieje sposób na otrzymywanie wydarzeń ORAZ przepuszczanie wydarzeń?
ticofab
@ticofab nie, tylko rodzic widoku aktualnie odbierającego zdarzenia może przechwycić przyszłe zdarzenia w geście. (Oczywiście zawsze możesz zbudować własne systemy przekierowań w widoku rodzica, ale nie polecałbym tego, chyba że naprawdę wiesz, co robisz. :))
adamp
@adamp Nie mogę wymyślić powodu, dla którego onTouch jest wywoływany 2 razy, gdy zwraca true i 1 raz tylko, gdy zwracam false.
Bhargav Jhaveri,
1
@adamp: zwracam false z ACTION_DOWN, ale moje ACTION_UP jest wyzwalane i wykonywane.
Mahantesh M Ambi
Czy ta odpowiedź jest błędna, czy wszyscy inni ... Ta odpowiedź mówi, że zwrot prawda oznacza, że ​​trudne wydarzenie nie zostanie skonsumowane. Ale prawda jest zupełnie odwrotna.
Kai Wang
12

Wartość logiczna określa, czy zdarzenie jest używane, czy nie.

Tak, masz rację. Jeśli zwrócisz wartość false, następny detektor obsłuży zdarzenie. Jeśli zwróci wartość true, zdarzenie jest używane przez odbiornik i nie jest wysyłane do następnej metody.

Falmarri
źródło
2
To nieprawda. trueoznacza, że ​​zdarzenie zostało zużyte i chcesz, aby reszta wydarzeń została zawarta w geście - inni słuchacze / widoki nie otrzymają zdarzeń. falseoznacza pozwolić komuś innemu zająć się wydarzeniem. W rzeczywistości jest to jednak nieco bardziej szczegółowe; zobacz moją odpowiedź.
adamp
Dlaczego to nie jest dokładnie to, co powiedziałem?
Falmarri
1
To, co powiedziałeś, jest odwrotne. :)
adamp
4

Wszystkie powyższe odpowiedzi są poprawne, ale wynik jest inny, czy widok jest, clickableczy nieclickable

Przykład , mam LinearLayoutzawiera 1 Buttoni 1 w TextViewten sposób

<LinearLayout
    android:id="@+id/linearlayout_root"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#0aa"
    android:orientation="vertical">

    <Button
        android:id="@+id/button_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="40dp"
        android:text="Button Click"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/textview_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="40dp"
        android:text="TextView Click"
        android:textSize="20sp"
        android:background="#e4e4e4"
        />

</LinearLayout>

W Aktywności mam kod podobny do

class MainActivity : AppCompatActivity() {
    val TAG = "TAG"

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<LinearLayout>(R.id.linearlayout_root).setOnTouchListener { v, event ->
            Log.i(TAG, "LinearLayout onTouch event " + getDisplayAction(event.action))
            false
        }

        findViewById<Button>(R.id.button_click).setOnTouchListener { v, event ->
            Log.i(TAG, "Button onTouch event " + getDisplayAction(event.action))
            false
        }

        findViewById<TextView>(R.id.textview_click).setOnTouchListener { v, event ->
            Log.i(TAG, "TextView onTouch event " + getDisplayAction(event.action))
            false
        }
    }

    private fun getDisplayAction(action: Int): String {
        return when (action) {
            MotionEvent.ACTION_DOWN -> "DOWN"
            MotionEvent.ACTION_MOVE -> "MOVE"
            MotionEvent.ACTION_UP -> "UP"
            MotionEvent.ACTION_CANCEL -> "CANCEL"
            MotionEvent.ACTION_OUTSIDE -> "OUTSIDE"
            else -> "UNKNOWN"
        }
    }
}

Przypadek 1 Linear onTouch return **FALSE**, Button onTouch return **FALSE**,TextView onTouch return **FALSE**

Kliknij przycisk

I/TAG: Button onTouch eventDOWN
I/TAG: Button onTouch eventMOVE
I/TAG: Button onTouch eventUP

Kliknij TextView

TAG: TextView onTouch eventDOWN
TAG: LinearLayout onTouch eventDOWN

Kliknij LinearLayout

TAG: LinearLayout onTouch eventDOWN

Przypadek 2 Linear onTouch return **FALSE**, Button onTouch return **TRUE**,TextView onTouch return **TRUE**

Kliknij przycisk

Similar to case 1

Kliknij TextView

TAG: TextView onTouch event DOWN
TAG: TextView onTouch event MOVE
TAG: TextView onTouch event UP

Kliknij LinearLayout

Similar to case 1

Przypadek 3 Linear onTouch return **TRUE**, Button onTouch return **FALSE**,TextView onTouch return **FALSE**

Kliknij przycisk

Similar to case 1

Kliknij TextView

TAG: TextView onTouch event DOWN
TAG: LinearLayout onTouch event DOWN
TAG: LinearLayout onTouch event MOVE
TAG: LinearLayout onTouch event UP

Kliknij LinearLayout

TAG: LinearLayout onTouch event DOWN
TAG: LinearLayout onTouch event MOVE
TAG: LinearLayout onTouch event UP

Uwaga

  • Domyślnie TextViewjest not clickableto klikalne, jeśli ustawimy android:clickable="true"w xml LUB kiedy ustawimytextView.setOnClickListener(...)
  • Podczas debugowania event MOVEmożna wywołać więcej niż mój dziennik (opiera się na tym, jak stukasz)

Podsumowanie

  • onTouchpowrót truelub widok jest clickable , widok otrzyma wszystko onTouchEvent
  • onTouchpowrót falsei widok nie jest clickable, widok nie otrzyma NEXT onTouchEvent (może go otrzymać jego rodzic)

Mam nadzieję, że pomoże to w
DEMO

Phan Van Linh
źródło
1
To powinna być odpowiedź! Dziękuję za tak szczegółowe wyjaśnienie
Mysterious_android
1

Straciłem prawie jeden dzień na rozwiązywaniu problemów, nadal odkryłem, że moja funkcja onTouch jest wywoływana 2 razy, gdy używam true i 1 razy, gdy używam false.

kamor
źródło
Czy możesz znaleźć powód?
Bhargav Jhaveri
sprawdź, event.getAction()ponieważ jeśli wrócisz falsena zdarzenie ACTION_DOWN, zdarzenie ACTION_UP jest ignorowane przez słuchacza
doodeec
0

Z dokumentu systemu Android :

Uwaga: system Android najpierw wywoła procedury obsługi zdarzeń, a następnie odpowiednie domyślne programy obsługi z definicji klasy. W związku z tym zwrócenie wartości true z tych detektorów zdarzeń zatrzyma propagację zdarzenia do innych detektorów zdarzeń, a także zablokuje wywołanie zwrotne do domyślnej procedury obsługi zdarzeń w widoku. Dlatego upewnij się, że chcesz zakończyć zdarzenie, gdy zwrócisz wartość true.

Huy Nguyen
źródło