为什么 android 认为我正在制作多点触控事件?

问题描述

给定:视图 A,包含视图 B。

my layout

动作:我用手指 1 触摸并按住视图 A,然后用手指 2 触摸视图 B。然后释放并执行相同的操作,但首先视图 B,然后视图 A。我希望在这两种情况下,视图都会收到类似的事件。

发生了什么:当我用手指 1 触摸并按住 A,然后用手指 2 触摸并按住 B 时,A 和 B 正在接收两个单独的 MotionEvents,它们每个都持有一个指针的 ACTION_MOVE 坐标:

Logcat:

-----first finger down on view A-------
    ACTION_DOWN[#0 (pid 0)=897,392]
    
    ----action move for first finger----
    ACTION_MOVE[#0 (pid 0)=897,392]
    ACTION_MOVE[#0 (pid 0)=897,392]
    ACTION_MOVE[#0 (pid 0)=895,392]
    ACTION_MOVE[#0 (pid 0)=896,393]
    ACTION_MOVE[#0 (pid 0)=896,394]
    ACTION_MOVE[#0 (pid 0)=896,395]
    ACTION_MOVE[#0 (pid 0)=896,396]
    ACTION_MOVE[#0 (pid 0)=895,396]
    
    ---second finger down on view B-------
    ACTION_DOWN[#0 (pid 1)=224,87]
    
    ---action move for 1st finger----
    ACTION_MOVE[#0 (pid 0)=895,396]
    
    ---action move for 2nd finger----
    ACTION_MOVE[#0 (pid 1)=224,87]
    
    --first--
    ACTION_MOVE[#0 (pid 0)=895,396]
    
    --second--
    ACTION_MOVE[#0 (pid 1)=224,87]
    
    etc . . .
    ACTION_MOVE[#0 (pid 0)=895,397]
    ACTION_MOVE[#0 (pid 1)=224,87]
    ACTION_MOVE[#0 (pid 0)=895,397]
    ACTION_MOVE[#0 (pid 1)=223,397]
    
        ...

但是,当我首先触摸 B,然后是 A - Android 认为这是一个 多点触摸 事件并开始发送 MotionEvent 对象,该对象包含 2 个 ACTION_MOVE 坐标仅指向视图 B。

Logcat:

   ----------holding finger at view B------------------
    event ACTION_MOVE[#0 (pid 0)=65,33]
    event ACTION_MOVE[#0 (pid 0)=62,33]
    event ACTION_MOVE[#0 (pid 0)=60,33]
    event ACTION_MOVE[#0 (pid 0)=58,33]
    event ACTION_MOVE[#0 (pid 0)=56,32]
    event ACTION_MOVE[#0 (pid 0)=55,32]
    event ACTION_MOVE[#0 (pid 0)=54,32]
    event ACTION_MOVE[#0 (pid 0)=53,32]
    event ACTION_MOVE[#0 (pid 0)=52,32]
    event ACTION_MOVE[#0 (pid 0)=51,33]
    
    ----------press on view A with 2nd finger,while holding B with first finger-------------
    event ACTION_POINTER_DOWN(pid 1); [#0 (pid 0)=51,33; #1 (pid 1)=1050,-226]
    
    ---------action move obj that holds coords for 2 pointers...---------
    event ACTION_MOVE[#0 (pid 0)=50,33;#1 (pid 1)=1055,-225]
    event ACTION_MOVE[#0 (pid 0)=48,34;#1 (pid 1)=1068,-223]
    event ACTION_MOVE[#0 (pid 0)=47,34;#1 (pid 1)=1082,-224]
    event ACTION_MOVE[#0 (pid 0)=45,35;#1 (pid 1)=1106,-221]
    event ACTION_MOVE[#0 (pid 0)=42,35;#1 (pid 1)=1131,-219]
    event ACTION_MOVE[#0 (pid 0)=38,35;#1 (pid 1)=1157,-217]
    event ACTION_MOVE[#0 (pid 0)=34,35;#1 (pid 1)=1178,-215]
    event ACTION_MOVE[#0 (pid 0)=27,36;#1 (pid 1)=1195,-213]
    event ACTION_MOVE[#0 (pid 0)=20,37;#1 (pid 1)=1211,-213]
    event ACTION_MOVE[#0 (pid 0)=11,39;#1 (pid 1)=1228,-212]

我想要的是:我想要在两种情况下(先是 A,然后是 B;先是 B,然后是 A)中的单独 MotionEvents(第一种情况)

我是如何解决这个问题的:

  1. 我尝试在视图 B 的 onTouch() 处仅处理 1 组坐标,然后返回 false,然后在视图 A 处消费事件,但在这种情况下,我在视图处除了 ACTION_DOWN 之外什么都没有收到B.

  2. 我尝试在 dispatchTouchEvent() 方法中分派活动中的事件,然后手动调用视图 A 和视图 B dispatchTouchEvent() 方法,但没有成功。我试图传递给 ViewGroup(父布局)但它也没有成功 =( onTouch 没有被调用

但是我认为这 2 次尝试是 HACK,我想让操作系统从多点触控切换回单独的触控事件。你知道怎么做吗?

解决方法

我刚刚创建了一个新项目,将布局设置为您的布局,然后为两个视图设置不同的“onTouch()”事件。我无法重现你的情况。如果两个“onTouch()”事件都返回 TRUE,则结果如下:

//DOWN for A
onTouchA(MotionEvent { action=ACTION_DOWN,actionButton=0,id[0]=0,x[0]=382.0,y[0]=175.0,toolType[0]=TOOL_TYPE_FINGER,buttonState=0,metaState=0,flags=0x0,edgeFlags=0x0,pointerCount=1,historySize=0,eventTime=10987450,downTime=10987450,deviceId=5,source=0x1002 })
onTouchA(MotionEvent { action=ACTION_MOVE,x[0]=365.0,y[0]=186.0,eventTime=10993036,source=0x1002 })
//DOWN for B
onTouchB(MotionEvent { action=ACTION_DOWN,id[0]=1,x[0]=409.0,y[0]=260.0,eventTime=10995795,x[0]=363.0,y[0]=184.0,source=0x1002 })
onTouchB(MotionEvent { action=ACTION_MOVE,y[0]=256.0,eventTime=10995888,x[0]=409.8291,y[0]=254.1709,historySize=1,eventTime=10995909,source=0x1002 })
//UP for A
onTouchA(MotionEvent { action=ACTION_UP,x[0]=361.0,y[0]=191.0,eventTime=10998121,x[0]=410.0,y[0]=234.0,eventTime=10998156,y[0]=235.0,eventTime=10998285,eventTime=10998460,x[0]=408.0,eventTime=10998530,source=0x1002 })
//UP for B
onTouchB(MotionEvent { action=ACTION_UP,x[0]=405.0,eventTime=10998846,source=0x1002 })

=================================

//DOWN for B
onTouchB(MotionEvent { action=ACTION_DOWN,x[0]=241.0,y[0]=195.0,eventTime=11125227,downTime=11125227,x[0]=221.0,y[0]=196.0,eventTime=11126010,x[0]=220.0,eventTime=11126044,source=0x1002 })
//DOWN for A
onTouchA(MotionEvent { action=ACTION_DOWN,x[0]=347.0,y[0]=156.0,eventTime=11128089,x[0]=216.0,eventTime=11129071,x[0]=343.0,eventTime=11130531,x[0]=219.91565,y[0]=194.0,eventTime=11132305,x[0]=337.0,eventTime=11133099,y[0]=157.0,eventTime=11133228,eventTime=11133240,source=0x1002 })

XML:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
    android:id="@+id/textView"
    android:layout_width="300dp"
    android:layout_height="400dp"
    android:background="@color/teal_200"
    android:text="Hello World!"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintHorizontal_bias="0.495"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.498" />
<TextView
    android:id="@+id/textView2"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:text="Hello World!"
    android:background="@color/teal_700"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

主活动代码:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextView cTextView = findViewById(R.id.textView);
    cTextView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v,MotionEvent event) {
            Log.e(TAG,"onTouchA("+event.toString()+")");
            return true;
        }
    });

    TextView cTextView2 = findViewById(R.id.textView2);
    cTextView2.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v,"onTouchB("+event.toString()+")");
            return false;
        }
    });
}
,

为了防止多点触控问题,您可以简单地关闭 ViewGroup 中的 splitMotionEvents 或 windowEnableSplitTouch 属性

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...