【问题标题】:Receiving onTouch and onClick events with Android使用 Android 接收 onTouch 和 onClick 事件
【发布时间】:2013-01-23 13:04:48
【问题描述】:

我有一个视图需要处理 onTouch 手势 onClick 事件。实现这一目标的正确方法是什么?

我在视图上设置了一个onTouchListener 和一个onClickListener。每当我触摸视图时,首先触发onTouch 事件,然后触发onClick。但是,从onTouch 事件处理程序我必须返回truefalse。返回true 表示该事件正在被消费,因此android 事件系统不会进一步传播该事件。

因此,永远不会生成onClick 事件,至少当我在onTouch 事件处理程序中返回true 时,永远不会触发我的onClick 侦听器。另一方面,返回false 没有选项,因为这会阻止onTouch 侦听器接收任何进一步的事件,这些事件是识别手势所必需的。解决这个问题的常用方法是什么?

【问题讨论】:

  • 为什么需要 onTouch 和 onClick?当然只有 onTouch 就足够了。
  • GestureDetector 怎么样?
  • @JDx 我应该如何识别来自onTouchListener 的点击?单击是至少两个触摸事件的序列,其中ACTION_DOWN 事件在与后面的ACTION_UP 事件完全相同的位置(或至少在同一视图上)触发。当然,可以实现这一点,如果没有其他解决方案,我会这样做。但我的问题确实是,这种场景是否有内置的解决方案?
  • @Keyser 我在OnGestureListener 中看不到任何类似 onClick 的回调
  • 检查它是否适用于我的解决方案stackoverflow.com/questions/19538747/…

标签: android android-event


【解决方案1】:

在您的 GestureDetector 中,您可以直接调用 callOnClick()。 请注意 View.callOnClick API 需要 API 级别 15。 试试看吧。

 // Create a Gesturedetector
GestureDetector mGestureDetector = new GestureDetector(context, new MyGestureDetector());

// Add a OnTouchListener into view
m_myViewer.setOnTouchListener(new OnTouchListener()
{

    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        return mGestureDetector.onTouchEvent(event);
    }
});

private class MyGestureDetector extends GestureDetector.SimpleOnGestureListener
{
    public boolean onSingleTapUp(MotionEvent e) {
        // ---Call it directly---
        callOnClick();
        return false;
    }

    public void onLongPress(MotionEvent e) {
    }

    public boolean onDoubleTap(MotionEvent e) {
        return false;
    }

    public boolean onDoubleTapEvent(MotionEvent e) {
        return false;
    }

    public boolean onSingleTapConfirmed(MotionEvent e) {
        return false;

    }

    public void onShowPress(MotionEvent e) {
        LogUtil.d(TAG, "onShowPress");
    }

    public boolean onDown(MotionEvent e) {            
        // Must return true to get matching events for this down event.
        return true;
    }

    public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, float distanceY) {
        return super.onScroll(e1, e2, distanceX, distanceY);
    }        

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // do something
        return super.onFling(e1, e2, velocityX, velocityY);
    }
}

【讨论】:

【解决方案2】:

如果您使用 onTouchListener ,则不必使用 onClickListener。在onClickListener 中,它的作用是获取触摸事件并检查事件操作并检测点击。所以如果你想在onClick时做一些工作。您可以通过过滤操作在onTouchListener 中执行此操作。

public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
    //this is touch

}
if (event.getAction() == MotionEvent.ACTION_UP) {
    //this is click

}
return false;
}

【讨论】:

  • 是否可以从MotionEvent.ACTION_UP 块内显式触发onClick-事件?
  • 还有:如果我的视图实际上是ViewGroup 并且它的一些子视图仍然需要处理onClick-Event 怎么办?
  • theV0ID,是的,可以通过调用 view.performClick()。
  • MotionEvent.ACTION_UP 不是点击。它只是意味着手指从屏幕上移开。即使在移动之后,当手指被移除时,它也会被调用。
【解决方案3】:
@Override
    public boolean onTouch(View v, MotionEvent event) {


        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                layOutParams.x = initialX + (int) (event.getRawX() - initialTouchX);
                layOutParams.y = initialY + (int) (event.getRawY() - initialTouchY);

                break;
            case MotionEvent.ACTION_DOWN:
                initialX = layOutParams.x;
                initialY = layOutParams.y;
                initialTouchX = event.getRawX();
                initialTouchY = event.getRawY();
                if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) {
                    return false;// to handle Click
                }
                break;
            case MotionEvent.ACTION_UP:
                if (initialTouchX == event.getRawX() && initialTouchY == event.getRawY()) {
                    return false;// to handle Click
                }
                break;

        }
        return true;

    }
};

【讨论】:

    【解决方案4】:
    isMove = false;
    case MotionEvent.ACTION_DOWN:
    //Your stuff
    isMove = false;
    case MotionEvent.ACTION_UP:
    if (!isMove || (Xdiff < 10 && Ydiff < 10 ) {
    view.performClick; //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little
    even when you just click it   
    }
    case MotionEvent.ACTION_MOVE:
    isMove = true;
    

    另一种方法是使用线程。那就是在 Action_Down 上启动一个线程来增加一个计数器。在 Action_UP 的情况下:停止/中断线程。如果计数器小于 2(根据您的应用程序说或阈值),则查找计数器或 !isMove 然后调用点击函数

    【讨论】:

      【解决方案5】:

      我已经能够在我正在构建的自定义键盘中同时实现 OnClick 和 OnTouch。您可以查看此代码并根据您的上下文对其进行修改,因为您没有包含可供使用的代码示例。

      如果您发布代码示例,我可以修改我的这个示例以实现相同的结果供您使用。当涉及到 Android 开发时,上下文就是一切。看看这段代码 sn-p 看看它是否有帮助。否则,请发布您自己的示例,我会进行修改并回复。

              View DefaultphaseLay() {
      
              LinearLayout mViewFirstPhase = (LinearLayout) getLayoutInflater().inflate(R.layout.layout_default_phase, parent);
      
              ksOne_btn_LiLay = (LinearLayout) mViewFirstPhase.findViewById(R.id.ksOne_btn_LiLay);
              ksOne_btn = (Button) mViewFirstPhase.findViewById(R.id.ksOne_btn);
              ksOne_btn.setOnClickListener(mCorkyListener);
              ksOne_btn.setFocusableInTouchMode(true);
              ksOne_btn.setFocusable(true);
              ksOne_btn.setOnTouchListener(new View.OnTouchListener() {
                  @Override
                  public boolean onTouch(View v, MotionEvent event) {
      
                      if (event.getAction() == MotionEvent.ACTION_DOWN) {
                          playClick(keyCode);
                          //v.startAnimation(animScale);
                          //key_sound.start();
                          xkeys_lay.setVisibility(View.GONE);
                          numkeys_lay.setVisibility(View.GONE);
                          if (Constants.HapticFeedbackConstant) {
                              myVib.vibrate(Constants.vibration_duration);
                          }
                      } else if (event.getAction() == MotionEvent.ACTION_UP) {
                          ksOne_btn.setFocusable(false); //Check This Added This In Attempt to Kill Selector on Action_Up
                          //playClick(-100);
                          //key_sound.pause();
                      }
                      return false;
                  }
              });
      
              ChangeKeyBackgroundMehods.initChange_Key_Background(ksOne_btn_LiLay);
              ChangeFontStyle.initChange_fontStyle(ksOne_btn, getApplicationContext());
              ChangeFont_size.initChange_fontSize(ksOne_btn, getApplicationContext());
      

      这适用于 alpha 或数字输出类型的上下文,如果事件要发送或使用其他需要修改的上下文。

      【讨论】:

      • 这是另一个使用 switch/case 与 if/else if 的示例,如下所示,但如果使用 alpha/numeric 必须确保管理按下状态和转换状态,否则最终会得到在 EditText 字段的输出中出现双字符。
      【解决方案6】:

      我们可以使用基于标志的实现。我们可以在 Action_Up 中处理滑动/拖动并使标志为真并返回相同的位置。如果在 Action_Down 中单击或点击相同的句柄并将标志设置为 false 并返回。

      touchAndSwipe=false;
      switch(e.getAction()){
          case MotionEvent.ACTION_MOVE:
              break;
          case MotionEvent.ACTION_DOWN:
              x1 = e.getX();
              break;
          case MotionEvent.ACTION_UP:
              x2 = e.getX();
              float diff = x2 - x1;
              if(Math.abs(delta) > 100) {
                  // Swipe
                  touchAndSwipe = true;
              } else {
                  touchAndSwipe = false;
              }
              break;
      }
      return touchAndSwipe;
      

      【讨论】:

        【解决方案7】:

        我同意 jdx,如果您使用 onTouchlistener,则不需要使用 onclicklistener,反之亦然,如果您想触发按钮、图像或文本视图单击事件,则只需触发 onClicklistener。如果你想要一些动画,比如拖动和旋转,那么使用 ontouchlistener 来获取被触摸表面的坐标

        【讨论】:

        • 如前所述:如果我的视图实际上是一个 ViewGroup 并且它的一些子视图仍然需要处理 onClick-Event 怎么办?
        • 在某些情况下,您需要有一个 onclick 和 ontouch 监听器。在 ACTION_UP 期间从 ontouch 内部生成点击事件是不同的。
        猜你喜欢
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多