【问题标题】:Android: custom view onClickEvent with X & Y locationsAndroid:带有 X 和 Y 位置的自定义视图 onClickEvent
【发布时间】:2016-03-21 01:34:16
【问题描述】:

我有一个自定义视图,我想获取用户点击的 X 和 Y 坐标。我发现我只能从 onTouchEvent 获取坐标,如果我有 onTouchEvent,onClickEvent 不会触发。不幸的是,当用户拖动屏幕以及点击时,onTouchEvent 会触发。

我试图区分这两者,但我在拖动时仍然会触发代码:

 public boolean onTouchEvent(MotionEvent event) {
  int action = event.getAction();
  if (action == MotionEvent.ACTION_DOWN) {
                //fires on drag and click

我查看了this,但正如我上面提到的,我认为那里的解决方案不会起作用,因为我无法让 onClick 和 onTouch 事件同时工作。也许我在这方面做错了什么,是否有一种正常的方法来处理捕获自定义事件的用户输入?我应该能够同时使用 onClick 和 onTouch 事件吗?

谢谢,马丁

【问题讨论】:

    标签: android view user-input


    【解决方案1】:

    您在 onTouchEvent 结束时返回什么?根据文档,返回 true 意味着“事件已被完全处理,不再做任何事情”,而返回 false 意味着系统将继续处理。我没有根据您的确切情况对此进行测试,但这表明返回 false 可能有效。这将使系统继续处理触摸/点击并将其发送到下一个“下方”视图。

    如果这不起作用,那么我想不出比做类似于 Rich 建议的事情更好的解决方案。你可以做一些事情,比如在 ACTION_DOWN 上获取时间,然后在 ACTION_UP 上,比较已经过去的时间。如果小于 100 毫秒,则应将其解释为单击。然后,您可以触发您想要放入点击侦听器的任何代码。

    例如,你可以这样编码:

    long touchDownTime; // This has to be a class field so that it persists 
                        // between calls to onTouchEvent
    
    public boolean onTouchEvent(MotioNEvent event){
        boolean handled = false;
    
        int action = event.getAction();
        switch (action){
        case MotionEvent.ACTION_DOWN:
            touchDownTime = SystemClock.elapsedRealtime();
            break;
    
        case MotionEvent.ACTION_UP:
            if (SystemClock.elapsedRealtime() - touchDownTime <= 100){
                int x = event.getX(); //or event.getRawX();
                int y = event.getY();
                performYourClick(x, y);
                handled = true;
            }
            break;
        }
    
        return handled;
    }
    

    注意:我实际上并没有测试该代码,所以我可能犯了一些语法错误。不过总体思路应该没问题。

    【讨论】:

    • 这个答案就是我想要的。查找 touchDownTime 的更简单方法是:long touchDownTime = event.getEventTime() - event.getDownTime(); 它不必是类字段。
    【解决方案2】:

    现在,我不知道 onTouchEvent 会导致 onClick 短路,也不知道您是否需要将 android:clickable 设置为 true(或 setClickable(true))。但是,如果你不能让它干净地工作,你可以在 onTouchEvent 中使用一个布尔值来模拟点击检测,如果所有其他方法都失败了。在 ACTION_DOWN 中,将其设置为 true(isClicking 或类似的东西),在 ACTION_MOVE 中将其设置为 false(因为用户正在拖动,因此不点击),然后在 ACTION_UP 中您可以对其进行测试。如果为真,则表示用户已按下但未拖动。这很 hacky,但如果你不能让 onClick 工作,那基本上是一样的。

    【讨论】:

    • 不幸的是,检查是否存在 ACTION_MOVE 无法可靠地工作 - 几乎不可能在不稍微移动手指的情况下手动单击。 (这是模拟器测试没有告诉你的事情之一......)你必须检查运动或时间延迟是否非常小。
    • 其实答案只是针对 MotionEvent.ACTION_UP 检查动作。显然,只有在单击而不是拖动时才会出现这种情况。
    • @Martyn:由于您的具体情况,可能会发生一些奇怪的事情,但通常当用户将手指从屏幕上移开时,总是会调用 ACTION_UP。假设将来拖动可能会以某种方式中断时不会发生这种情况,例如在使用不同版本的 Android 时,或者如果您更改要扩展的根视图类型。 (特别是 WebView 的行为非常奇怪,请注意:P)
    【解决方案3】:

    仅供参考,在我的测试中,无论 onTouch 返回 true 还是 false,看起来 onTouch 确实会覆盖 onClick 的视图。

    -弗林克

    【讨论】:

      【解决方案4】:

      我已经解决了这个问题

      我创建了一个自定义视图公共类 QuestionBuilderView extends View

      在布局文件中

       < com.example.android.view.QuestionBuilderView
      
              android:id="@+id/questionbuilderview"
      
              android:layout_width="fill_parent"
      
              android:layout_height="wrap_content" />
      

      在主 Activity 中尝试调用自定义视图并将 Onclick / On Touch 事件侦听器设置为视图

       View questionBuilder =  findViewById(R.id.questionbuilderview);
               questionBuilder.setOnTouchListener(new OnTouchListener() {
      
                  @Override
                  public boolean onTouch(View view, MotionEvent event) {
                      // TODO Auto-generated method stub
                      float touched_x = event.getX();
                     float  touched_y = event.getY();
                     Toast.makeText(getApplicationContext(), " "+touched_x +","+touched_y, Toast.LENGTH_LONG).show();
                    //  int action = event.getAction();
      
      
                      return true;
                  }
      

      【讨论】:

        【解决方案5】:

        我认为你必须调用 super.onTouchEvent(event) 因为在那个方法中,点击被检测到。

        【讨论】:

          【解决方案6】:

          您应该使用GestureDetector。子类GestureDetector.SimpleOnGestureListener 并覆盖onDown(MotionEvent event) 方法以返回true。然后覆盖onSingleTapConfirmed。将侦听器传递给GestureDetector 构造函数。然后以该监听器作为参数调用setOnDoubleTapListener

          // in your view class constructor
          GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {
             @Override
             public boolean onDown(MotionEvent e) {
                return true;
             }
             @Override
             public boolean onSingleTapConfirmed(MotionEvent e) {
                // do whatever you want
                return true;
             }
          };
          mDetector = new GestureDetector(getContext(), listener);
          mDetector.setOnDoubleTapListener(listener);
          

          然后,您可以将MotionEvents 传递给检测器:

          @Override
          public boolean onTouchEvent(MotionEvent event) {
             return mDetector.onTouchEvent(event);
          }
          

          【讨论】:

            猜你喜欢
            • 2016-09-23
            • 1970-01-01
            • 2021-02-23
            • 2013-12-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-28
            • 2016-01-18
            相关资源
            最近更新 更多