OnClickListener - 事件的 x、y 坐标位置?

92

我有一个自定义视图,派生自View。我想在视图被点击时得到通知,并获得单击发生的x,y位置和长按发生的位置。

看起来要做到这一点,我需要覆盖onTouchEvent()。但是,是否没有办法从OnClickListener获取事件的x,y位置呢?

如果不行,如何判断运动事件是“真正”的点击而不是长按等事件?onTouchEvent会快速生成许多事件等。

4个回答

95

谢谢,这正是我在寻找的。现在我的代码是:

imageView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN){
                textView.setText("Touch coordinates : " +
                        String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
            }
            return true;
        }
    });

这正是Mark所要求的...


4
这些坐标是相对于视图的本地坐标系吗? - Nigel
7
onTouch处理程序应该返回 false ,以便不会阻塞触摸事件。(如果监听器已消耗事件,则View.OnTouchListener.onTouch返回true,否则返回false。) - ehartwell
7
好的,不是“精确”地,在手指释放时会触发OnClickListener,因此在 ACTION_UP 中,但有限制:如果执行了 fling (swipe) 手势,则不会触发OnClickListener,但 ACTION_UP 仍将被处理。 - Alex Semeniuk
我正在尝试在鼠标点击的坐标上写入文本。我尝试在坐标(event.getX(), event.getY())处写入文本,但它没有写在正确的位置。 - Prince
这是我的问题:http://stackoverflow.com/questions/40199539/how-to-appropriately-write-text-on-the-clicked-co-ordinates-of-the-image - Prince
OP的问题是检测点击坐标。这个解决方案获取的是鼠标按下事件,而不是点击事件。Suragch在这里提供了一个实际上可以获取点击位置的答案。 - CBGraham

29

完整示例

其他答案缺少一些细节。这里是一个完整的示例。

public class MainActivity extends AppCompatActivity {

    // class member variable to save the X,Y coordinates
    private float[] lastTouchDownXY = new float[2];

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

        // add both a touch listener and a click listener
        View myView = findViewById(R.id.my_view);
        myView.setOnTouchListener(touchListener);
        myView.setOnClickListener(clickListener);
    }

    // the purpose of the touch listener is just to store the touch X,Y coordinates
    View.OnTouchListener touchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            // save the X,Y coordinates
            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                lastTouchDownXY[0] = event.getX();
                lastTouchDownXY[1] = event.getY();
            }

            // let the touch event pass on to whoever needs it
            return false;
        }
    };

    View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // retrieve the stored coordinates
            float x = lastTouchDownXY[0];
            float y = lastTouchDownXY[1];

            // use the coordinates for whatever
            Log.i("TAG", "onLongClick: x = " + x + ", y = " + y);
        }
    };
}

摘要

  • 添加一个类变量来存储坐标
  • 使用OnTouchListener保存X,Y坐标
  • OnClickListener中访问X,Y坐标

2
可以使用Point(),而不是一个2空格float数组。 - ZooMagic
点有整数类型的X和Y。坐标是浮点值。如果我使用Point类,我认为我会失去精度...我在Android方面非常新,可能我错过了什么。 - mboada
1
@mboada,你是对的。PointF会更好。 - Suragch
应该有一种方法可以避免使用onTouchListener,而只使用onClickListener。不知何故,ContextMenu不需要它。在点击一个项目并显示菜单时,视图作为锚点,它知道将其放置在哪里,靠近触摸位置。请参见:https://dev59.com/sbXna4cB1Zd3GeqPKm7Q。你知道这是如何实现的吗?如果知道,请考虑在那里回答。 - android developer

3

覆盖 onTouchEvent(MotionEvent ev) 方法

然后你可以这样做:

ev.getXLocation()

或者类似的东西。看一下。


2
嗨Tom,是的,我们可以使用onTouchEvent,但是这样我们需要自己处理区分单击和长按,不是吗?在OnClickListener等中,他们没有提供一种知道单击或长按发生位置的方法是没有意义的,对吧?谢谢。 - Mark
21
你只需记录最后一个ACTION_UP或ACTION_MOVE事件的x和y位置,并在你的OnClickListener中使用这些值即可。 - Romain Guy
@RomainGuy 但是你还必须计算两点之间的距离来确定点击事件。如果你在(0,0)处收到ACTION_DOWN事件,然后在(100,100)处收到ACTION_UP事件,那肯定不是一个点击事件。 - TheRealChx101
@chx101,我认为RomainGuy的意思是,如果你只在touchevent中记录最后一个action_up坐标,那么这些坐标就可以在onclick中使用。但是我认为实际上需要对视图进行子类化,否则onclick不会被调用。你也可以将轻击检测作为手势检测器来检测,例如https://dev59.com/N2Ik5IYBdhLWcg3wJ7P4答案中所述。 - Lassi Kinnunen

3
你可以在 Kotlin 中创建一个扩展函数,像这样:

你可以在 Kotlin 中创建一个扩展函数,就像这样:

fun View.setOnClickListenerWithPoint(action: (Point) -> Unit) {
    val coordinates = Point()
    val screenPosition = IntArray(2)
    setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_DOWN) {
            v.getLocationOnScreen(screenPosition)
            coordinates.set(event.x.toInt() + screenPosition[0], event.y.toInt() + screenPosition[1])
        }
        false
    }
    setOnClickListener {
        action.invoke(coordinates)
    }
}

如果你需要长按 - 只需替换setOnClickListener 我使用getLocationOnScreen(),因为我需要 RecyclerView 的 ViewHolder 的坐标。

如何使用? - seekingStillness

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