Android 如何将手势检测器添加到视图
How to add a gesture detector to a view in Android
我一直在努力将手势检测器添加到我项目的子视图中。我是要覆盖 parent 的 onTouchEvent
还是 child 的 onTouchEvent
?我是否制作 OnTouchListener
并在其中添加手势检测器? documentation shows an example for how to add a gesture detector to the activity itself but it is not clear how to add it to a view. The same process could be used if subclassing a view (example here),但我想添加手势而不子类化任何东西。
This 是我能找到的最接近的其他问题,但它特定于 ImageView
上的投掷手势,而不是任何 View
的一般情况。对于何时 return true
或 false
,这些答案也存在一些分歧。
为了帮助自己理解它是如何工作的,我做了一个独立的项目。我的回答如下。
此示例演示如何将手势检测器添加到视图。布局只是 Activity 内的单个 View
。您可以使用相同的方法将手势检测器添加到任何类型的视图。
我们将把手势检测器添加到绿色View
。
MainActivity.java
基本思路是在视图中添加一个OnTouchListener
。通常我们会在这里获取所有原始触摸数据(如 ACTION_DOWN
、ACTION_MOVE
、ACTION_UP
等),但我们不会自己处理,而是将其转发到手势检测器做触摸数据的解释。
我们正在使用 SimpleOnGestureListener
。这个手势检测器的好处是我们只需要覆盖我们需要的手势。在这里的示例中,我包含了很多。您可以删除不需要的。 (不过,您应该始终在 onDown()
中 return true
。返回 true 意味着我们正在处理该事件。返回 false 将使系统停止为我们提供更多触摸事件。)
public class MainActivity extends AppCompatActivity {
private GestureDetector mDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this is the view we will add the gesture detector to
View myView = findViewById(R.id.my_view);
// get the gesture detector
mDetector = new GestureDetector(this, new MyGestureListener());
// Add a touch listener to the view
// The touch listener passes all its events on to the gesture detector
myView.setOnTouchListener(touchListener);
}
// This touch listener passes everything on to the gesture detector.
// That saves us the trouble of interpreting the raw touch events
// ourselves.
View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// pass the events to the gesture detector
// a return value of true means the detector is handling it
// a return value of false means the detector didn't
// recognize the event
return mDetector.onTouchEvent(event);
}
};
// In the SimpleOnGestureListener subclass you should override
// onDown and any other gesture that you want to detect.
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent event) {
Log.d("TAG","onDown: ");
// don't return false here or else none of the other
// gestures will work
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("TAG", "onSingleTapConfirmed: ");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
Log.i("TAG", "onLongPress: ");
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("TAG", "onDoubleTap: ");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("TAG", "onScroll: ");
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
Log.d("TAG", "onFling: ");
return true;
}
}
}
这是 运行 这个项目的快速设置,因此我建议您尝试一下。注意日志事件发生的方式和时间。
kotlin 中的简短版本,仅针对视图检测双击:
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
override fun onDoubleTap(e: MotionEvent?): Boolean {
Log.d("myApp", "double tap")
return true
}
})
myView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
别忘了让 myView
可点击
我一直在努力将手势检测器添加到我项目的子视图中。我是要覆盖 parent 的 onTouchEvent
还是 child 的 onTouchEvent
?我是否制作 OnTouchListener
并在其中添加手势检测器? documentation shows an example for how to add a gesture detector to the activity itself but it is not clear how to add it to a view. The same process could be used if subclassing a view (example here),但我想添加手势而不子类化任何东西。
This 是我能找到的最接近的其他问题,但它特定于 ImageView
上的投掷手势,而不是任何 View
的一般情况。对于何时 return true
或 false
,这些答案也存在一些分歧。
为了帮助自己理解它是如何工作的,我做了一个独立的项目。我的回答如下。
此示例演示如何将手势检测器添加到视图。布局只是 Activity 内的单个 View
。您可以使用相同的方法将手势检测器添加到任何类型的视图。
我们将把手势检测器添加到绿色View
。
MainActivity.java
基本思路是在视图中添加一个OnTouchListener
。通常我们会在这里获取所有原始触摸数据(如 ACTION_DOWN
、ACTION_MOVE
、ACTION_UP
等),但我们不会自己处理,而是将其转发到手势检测器做触摸数据的解释。
我们正在使用 SimpleOnGestureListener
。这个手势检测器的好处是我们只需要覆盖我们需要的手势。在这里的示例中,我包含了很多。您可以删除不需要的。 (不过,您应该始终在 onDown()
中 return true
。返回 true 意味着我们正在处理该事件。返回 false 将使系统停止为我们提供更多触摸事件。)
public class MainActivity extends AppCompatActivity {
private GestureDetector mDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this is the view we will add the gesture detector to
View myView = findViewById(R.id.my_view);
// get the gesture detector
mDetector = new GestureDetector(this, new MyGestureListener());
// Add a touch listener to the view
// The touch listener passes all its events on to the gesture detector
myView.setOnTouchListener(touchListener);
}
// This touch listener passes everything on to the gesture detector.
// That saves us the trouble of interpreting the raw touch events
// ourselves.
View.OnTouchListener touchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// pass the events to the gesture detector
// a return value of true means the detector is handling it
// a return value of false means the detector didn't
// recognize the event
return mDetector.onTouchEvent(event);
}
};
// In the SimpleOnGestureListener subclass you should override
// onDown and any other gesture that you want to detect.
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent event) {
Log.d("TAG","onDown: ");
// don't return false here or else none of the other
// gestures will work
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.i("TAG", "onSingleTapConfirmed: ");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
Log.i("TAG", "onLongPress: ");
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("TAG", "onDoubleTap: ");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
Log.i("TAG", "onScroll: ");
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
Log.d("TAG", "onFling: ");
return true;
}
}
}
这是 运行 这个项目的快速设置,因此我建议您尝试一下。注意日志事件发生的方式和时间。
kotlin 中的简短版本,仅针对视图检测双击:
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
override fun onDoubleTap(e: MotionEvent?): Boolean {
Log.d("myApp", "double tap")
return true
}
})
myView.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
别忘了让 myView
可点击