Android中事件处理方法返回的布尔值是什么意思?

113
在Android中,大多数事件监听器方法会返回一个布尔值。这个true/false值表示什么?会对后续事件有什么影响吗?

在Android中,大多数事件监听器方法都会返回布尔值。这个true/false值表示是否已处理该事件。如果返回true,则表示该事件已被处理,后续事件将不再受到影响;如果返回false,则表示该事件未被处理,后续事件仍将继续尝试处理该事件。

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

针对上述示例,如果在onTouch方法中返回true,我发现每个触摸事件(DOWN、UP、MOVE等)都已经被捕获,根据我的logView。相反,如果返回false,则只捕获DOWN事件。因此,似乎返回false将阻止事件传播。我的理解正确吗?

此外,在OnGestureListener中,许多方法也必须返回一个布尔值。它们的含义相同吗?

6个回答

145
如果你在 ACTION_DOWN 事件中返回了 true,就表示你对该手势的其余事件感兴趣。在这种情况下,“手势”指的是直到最终的 ACTION_UPACTION_CANCEL 的所有事件。如果在 ACTION_DOWN 中返回 false,则表示你不想要这个事件,其他视图将有机会处理它。如果你有重叠的视图,那么这可以是一个兄弟视图。如果没有,它将冒泡到父级视图。

3
Adamp,有没有一种方法可以继续接收事件,同时让这些事件通过呢? - ticofab
@ticofab 不,只有当前接收事件的视图的父级才能拦截未来的手势事件。(当然,你总是可以在父视图中构建自己的重定向系统,但我不建议这样做,除非你真的知道你在做什么。 :) ) - adamp
@adamp 我想不出为什么当我返回true时,onTouch会被调用2次,而当我返回false时只调用1次。 - Bhargav Jhaveri
1
@adamp:我从ACTION_DOWN返回false,但我的ACTION_UP被触发并执行了。 - Mahantesh M Ambi
我是否理解错了这个回复,还是其他人也是一样的... 这个回复说返回 true 意味着强事件没有被消耗。但事实完全相反。 - Kai Wang

25

13

布尔值确定事件是否被消耗。

是的,你是正确的。如果返回 false,则下一个监听器处理该事件。如果返回 true,则您的监听器将消耗该事件,并且不会将其发送到下一个方法。


2
这是错误的。true 表示您已消耗事件并希望手势中的其余事件 - 其他侦听器/视图将不会接收事件。 false 表示让其他人处理事件。实际上,它比那更具体;请参见我的答案。 - adamp
那不就是我说的吗? - Falmarri
1
你说的是反过来的。 :) - adamp

4

以上所有答案都是正确的,但结果的不同在于View是否可点击clickable

例如,我有一个包含1个Button和1个TextViewLinearLayout,如下所示

<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>

在Activity中,我有以下代码:
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"
        }
    }
}

案例1:线性触摸返回**FALSE**按钮触摸返回**FALSE**文本视图触摸返回**FALSE**

点击按钮

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

Click on TextView

TAG: TextView onTouch eventDOWN
TAG: LinearLayout onTouch eventDOWN

Click on LinearLayout

TAG: LinearLayout onTouch eventDOWN

案例2: Linear onTouch 返回 **FALSE**Button onTouch 返回 **TRUE**TextView onTouch 返回 **TRUE**

点击按钮

Similar to case 1

Click on TextView

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

点击LinearLayout

Similar to case 1

案例3 Linear onTouch 返回 **TRUE**Button onTouch 返回 **FALSE**TextView onTouch 返回 **FALSE**

点击按钮

Similar to case 1

点击 TextView

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

点击 LinearLayout

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

注意

  • TextView 的默认值为不可点击,如果我们在xml中设置android:clickable="true"或者使用textView.setOnClickListener(...)来设置,它将变得可点击。
  • 当您调试时,MOVE事件可能会调用多次(这取决于您的点击方式)。

总结

  • 如果onTouch返回true或视图是clickable,则视图将接收所有onTouchEvent
  • 如果onTouch返回false且视图不可clickable,则视图将不会接收下一个onTouchEvent(其父级可能会接收它)。

希望这有所帮助
演示


1
这应该是答案!感谢您提供如此详细的解释。 - Mysterious_android

1

我在故障排除上浪费了将近一天的时间,最终发现当使用true时,我的onTouch函数被调用了2次,而使用false时只调用了1次。


你能找出原因吗? - Bhargav Jhaveri
请检查event.getAction(),因为如果在ACTION_DOWN事件上返回false,则ACTION_UP事件将被监听器忽略。 - doodeec

0

来自Android-document

注意:Android会先调用事件处理程序,然后再从类定义中调用适当的默认处理程序。因此,从这些事件侦听器返回true将停止将事件传播到其他事件侦听器,并且还将阻止回调到View中的默认事件处理程序。因此,请确保在返回true时要终止事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接