【问题标题】:Android - how to detect a touch on screen is a "scroll" touch?Android - 如何检测屏幕上的触摸是“滚动”触摸?
【发布时间】:2016-02-09 13:17:43
【问题描述】:

我正在用 Java 创建一个 android 应用程序,其中我在屏幕周围有很多 <TextView>,所有这些都定义了 onTouchListeners。它们被包裹在 <ScrollView> 中,因为它们占用的空间比屏幕上可用的空间多。

我的问题是:当我通过触摸屏幕并向上/向下移动手指来向上/向下滚动应用程序时,滚动按预期工作,但触摸 <TextView> 的 onTouchListener 也会被触发(即可能也是预期的) - 我不希望这种情况发生。我希望在触摸屏幕滚动时忽略 onTouchListener。

我怎样才能做到这一点?我不希望我的函数在用户滚动并且“意外”在某个 <TextView> 上触发 onTouchListener 时运行。

【问题讨论】:

标签: java android android-scrollview android-touch-event


【解决方案1】:

经过更多搜索,我找到了 Stimsoni 的this solution。这个想法是检查ACTION_DOWNACTION_UP 事件之间的时间是否低于或高于ViewConfiguration.getTapTimeout() 给出的值。

来自文档:

[返回] 我们将等待查看触摸事件是点击还是滚动的持续时间(以毫秒为单位)。如果用户在此间隔内没有移动,则认为是点击。

代码:

view.setOnTouchListener(new OnTouchListener() {

    private long startClickTime;

    @Override
    public boolean onTouch(View view, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {

            startClickTime = System.currentTimeMillis();

        } else if (event.getAction() == MotionEvent.ACTION_UP) {

            if (System.currentTimeMillis() - startClickTime < ViewConfiguration.getTapTimeout()) {

                // Touch was a simple tap. Do whatever.

            } else {

                // Touch was a not a simple tap.

            }

        }

        return true;
    }

});

【讨论】:

  • @Chris623 谢谢!很高兴它有帮助。
【解决方案2】:

我和你有同样的问题,我用ACTION_CANCEL解决了。

motionEvent.getActionMasked() 等于 ACTION_CANCEL,当先前感知的动作(如您的情况下的 ACTION_DOWN)现在被其他手势(如滚动等)“取消”时。您的代码可能是这样的:

view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent e) {
        if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
            // perceive a touch action.
        } else if(e.getActionMasked() == MotionEvent.ACTION_UP ||
                e.getActionMasked() == MotionEvent.ACTION_CANCEL) {
            // ignore the perceived action.      
        }
    }

我希望这会有所帮助。

【讨论】:

    【解决方案3】:

    我遇到了类似的问题,但使用一个 TextView,搜索将我带到了这里。文本内容可能占用比屏幕上可用空间更多的空间。 简单的工作示例:bpmcounter-android (Kotlin)

    class MainActivity : AppCompatActivity() {
    
        inner class GestureTap : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent?): Boolean {
                // Do your buttonClick stuff here. Any scrolling action will be ignored
                return true
            }
        }
    
        @SuppressLint("ClickableViewAccessibility")
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val textView = findViewById<TextView>(R.id.textView)
            textView.movementMethod = ScrollingMovementMethod()
            val gestureDetector = GestureDetector(this, GestureTap())
            textView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
        }
    }
    

    【讨论】:

      【解决方案4】:

      1 种方法:

      我发现最好的方法是检测第一次触摸保存点 x 和 y,然后用第二次触摸来面对它。如果第一次点击和第二次点击之间的距离很近(我把 10% 作为近似值),那么触摸一个简单的点击,否则就是一个滚动动作。

       /**
       * determine whether two numbers are "approximately equal" by seeing if they
       * are within a certain "tolerance percentage," with `tolerancePercentage` given
       * as a percentage (such as 10.0 meaning "10%").
       *
       * @param tolerancePercentage 1 = 1%, 2.5 = 2.5%, etc.
       */
      fun approximatelyEqual(desiredValue: Float, actualValue: Float, tolerancePercentage: Float): Boolean {
          val diff = Math.abs(desiredValue - actualValue) //  1000 - 950  = 50
          val tolerance = tolerancePercentage / 100 * desiredValue //  20/100*1000 = 200
          return diff < tolerance //  50<200      = true
      }
      
      var xPoint = 0f
      var yPoint = 0f
      @SuppressLint("ClickableViewAccessibility")
      override fun onTouchEvent(event: MotionEvent): Boolean {
          when(event.action) {
      
              MotionEvent.ACTION_DOWN -> {
                  xPoint = event.x
                  yPoint = event.y
                  return true
              }
      
              MotionEvent.ACTION_UP -> {
                  if (!approximatelyEqual(xPoint, event.x, 10f) || !approximatelyEqual(yPoint, event.y, 10f)) {
                      //scrolling
                  } else {
                      //simple click
                  }
              }
          }
          return false
      }
      

      2 方法:

      做同样事情的另一种方法是使用 GestureDetector 类:

         interface GestureInterface {
          fun setOnScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float)
          fun onClick(e: MotionEvent)
      }
      
      class MyGestureDetector(val gestureInterfacePar: GestureInterface) : SimpleOnGestureListener() {
      
          override fun onSingleTapUp(e: MotionEvent): Boolean { 
              gestureInterfacePar.onClick(e)
              return false
          }
      
          override fun onLongPress(e: MotionEvent) {}
          override fun onDoubleTap(e: MotionEvent): Boolean {
              return false
          }
      
          override fun onDoubleTapEvent(e: MotionEvent): Boolean {
              return false
          }
      
          override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
              return false
          }
      
          override fun onShowPress(e: MotionEvent) {
          }
      
          override fun onDown(e: MotionEvent): Boolean { 
              return true
          }
      
          override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
              gestureInterfacePar.setOnScroll(e1, e2, distanceX, distanceY)
              return false
          }
      
          override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { 
              return super.onFling(e1, e2, velocityX, velocityY)
          }
      }
      

      最后,将它与您的视图绑定:

      val mGestureDetector = GestureDetector(context, MyGestureDetector(object : GestureInterface {
                      override fun setOnScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float) {
                          //handle the scroll
                      }
      
                      override fun onClick(e: MotionEvent) {
                          //handle the single click
                      }
      
                  }))
      
      
                  view.setOnTouchListener(OnTouchListener { v, event -> mGestureDetector.onTouchEvent(event) })
      

      【讨论】:

      • 我想这也是有道理的。但是,当前接受的答案对您来说不够好,是否有原因?
      • 旁注:您不应在第一种方法中使用百分比,而应使用固定容差值。否则,如果 x=100,容差将为 10px,如果 x=1000,则容差为 100px,如果 x=10,则容差为 1px。您不希望屏幕左侧的容忍度低于屏幕右侧:)
      【解决方案5】:

      您可以像这样识别移动动作:

      view.setOnTouchListener(new View.OnTouchListener() {
              @Override
              public boolean onTouch(View v, MotionEvent event) {
      
                  if(event.getAction() == MotionEvent.ACTION_MOVE)
                  {
      
                  }
      
                  return false;
              }
          });
      

      【讨论】:

      • 谢谢;虽然并没有真正解决我的问题,但它给了我更多搜索的想法,我能够解决问题。非常感谢。
      【解决方案6】:

      为我工作:

      View.OnTouchListener() {
      
      @Override
      
      public boolean onTouch(View v,MotionEvent event)
      {
              if(event.getAction()!=MotionEvent.ACTION_DOWN)
              {
                           // Before touch
              }
              else {
                            // When touched
                   }
      
        return true
      });
      

      【讨论】:

        【解决方案7】:

        您不需要采用这种复杂的方法来捕获“点击”事件。仅针对此方法:-

        //当然是在触摸监听器里面:-

        科特林:-

        if(event.action == MotionEvent.ACTION_UP && event.action != MotionEvent.ACTION_MOVE) {
        // Click has been made...
        // Some code
        }
        

        JAVA :- 只需将 event.action 替换为 event.getAction()

        这对我有用?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-07-06
          • 2012-02-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多