【问题标题】:OnClickListener - x,y location of event?OnClickListener - 事件的 x,y 位置?
【发布时间】:2009-12-27 21:03:33
【问题描述】:

我有一个从 View 派生的自定义视图。我希望在单击视图时收到通知,以及单击发生位置的 x、y 位置。长按也是一样。

看起来要这样做,我需要覆盖onTouchEvent()。不过,有没有办法从OnClickListener 获取事件的 x,y 位置?

如果不是,那么有什么好方法可以判断动作事件是“真正的”点击还是长按等? onTouchEvent 快速连续生成许多事件等。

【问题讨论】:

    标签: android


    【解决方案1】:

    谢谢。这正是我想要的。我现在的代码是:

    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 要求的...

    【讨论】:

    • 这些坐标是视图的本地坐标吗?
    • 不应该 onTouch 处理程序返回false 这样它就不会阻止触摸事件吗? (View.OnTouchListener.onTouch 如果监听器已经消费了事件,则返回 true,否则返回 false。)
    • 好吧,不是“精确地”,因为OnClickListener 在手指释放时被触发,所以在ACTION_UP 中但有限制:如果 f.i.执行了滑动(滑动)手势,然后OnClickListener 不会被触发,但ACTION_UP 仍将被处理。
    • 我正在尝试在点击的坐标上写文字。我尝试在坐标(event.getX(), event.getY()) 处写文字,但它没有写在正确的位置。
    【解决方案2】:

    完整示例

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

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

    【讨论】:

    • 可以使用 Point() 代替 2 个空格的浮点数组。
    • Point 具有整数类型的 X 和 Y。坐标是浮点值。如果我使用 Point 类,我想我会失去精度......我是 Android 的新手,可能我错过了一些东西。
    • @mboada,你是对的。 PointF 会更好。
    • 应该有办法避免onTouchListener,只使用onClickListener。不知何故,ContextMenu 不需要它。在单击一个项目并以视图作为锚点显示菜单时,它知道将其放置在触摸位置附近的位置。见这里:stackoverflow.com/q/57290574/878126。你知道怎么可能吗?如果是这样,请考虑在那里回答。
    【解决方案3】:

    覆盖 onTouchEvent(MotionEvent ev)

    那么你可以这样做:

    ev.getXLocation()
    

    或者类似的东西。吃肉吧。

    【讨论】:

    • 嗨,Tom,是的,我们可以使用 onTouchEvent,但是我们需要自己处理点击和长点击之间的区别,不是吗?他们不会为您提供一种了解单击或长按在 OnClickListener 等中发生的位置的方法是没有意义的?谢谢
    • 您所要做的就是记录最后一个 ACTION_UP 或 ACTION_MOVE 事件的 x & y 位置,并在您的 OnClickListener 中使用这些值。
    • @RomainGuy 但是您还必须计算两点之间的距离以确定点击。如果您在 (0,0) 处收到 ACTION_DOWN 事件,然后在 (100,100) 处收到 ACTION_UP 事件,那绝对不是点击。
    • @chx101,RomainGuy 的意思(我认为)是,如果您只是在 touchevent 上记录最后一个 action_up 坐标,那么这些就是您可以在 onclick 中使用的坐标。但是我认为这需要在实践中对视图进行子类化,否则不会调用 onclick。您还可以将点击检测为手势检测器,如stackoverflow.com/questions/19538747/… answer
    【解决方案4】:

    你可以在 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 的坐标

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 2022-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多