Android 时间处理机制 OnTouchListener 和 OnGestureListener
Android 事件处理机制是基于 Listener 实现的,比如触摸屏相关的事件,是通过 OnTouchListener 实现的;而手势是通过 OnGestureListener 实现的,那么这两者有什么关联呢?
OnTouchListener
OnTouchListener 接口中包含一个 onTouch() 方法,直接看一个例子:
public class MainActivity extends Activity implements OnTouchListener {
public void onCreate(Bundle outState) {
super.onCreate(outState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(this, "Touch Touch", Toast.LENGTH_SHORT).show();
return false ;
}
}
我们可以通过 MotionEvent 的 getAction() 方法来获取 Touch 事件的类型,包括 ACTION_DOWN(按下触摸屏), ACTION_MOVE(按下触摸屏后移动受力点), ACTION_UP(松开触摸屏)和 ACTION_CANCEL(不会由用户直接触发)。借助对于用户不同操作的判断,结合 getRawX()、 getRawY()、getX() 和 getY() 等方法来获取坐标后,我们可以实现诸如拖动某一个按钮,拖动滚动条等功能。
可以看到 OnTouchListener 只能监听到三种触摸事件,即按下,移动,松开,如果想要监听到双击、滑动、长按等复杂的手势操作,这个时候就必须得用到 OnGestureListener 了。
OnGestureListener
接着上面的例子,这次加入手势监听:
public class MainActivity extends Activity implements OnTouchListener, OnGestureListener {
private GestureDetector mGestureDetector;
public void onCreate(Bundle outState) {
super.onCreate(outState);
setContentView(R.layout.main);
mGestureDetector = new GestureDetector(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
// 用户轻触触摸屏,由 1 个 MotionEvent ACTION_DOWN 触发
public boolean onDown(MotionEvent arg0) {
Log.i("MyGesture", "onDown");
Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
return true;
}
// 用户轻触触摸屏,尚未松开或拖动,由一个 1 个 MotionEvent ACTION_DOWN 触发, 注意和 onDown() 的区别,强调的是没有松开或者拖动的状态
public void onShowPress(MotionEvent e) {
Log.i("MyGesture", "onShowPress");
Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
}
// 用户(轻触触摸屏后)松开,由一个 1 个 MotionEvent ACTION_UP 触发
public boolean onSingleTapUp(MotionEvent e) {
Log.i("MyGesture", "onSingleTapUp");
Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
return true;
}
// 用户按下触摸屏、快速移动后松开,由 1 个 MotionEvent ACTION_DOWN, 多个 ACTION_MOVE, 1 个 ACTION_UP 触发
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.i("MyGesture", "onFling");
Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
return true;
}
// 用户按下触摸屏,并拖动,由 1 个 MotionEvent ACTION_DOWN, 多个 ACTION_MOVE 触发
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.i("MyGesture", "onScroll");
Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
return true;
}
// 用户长按触摸屏,由多个 MotionEvent ACTION_DOWN 触发
public void onLongPress(MotionEvent e) {
Log.i("MyGesture", "onLongPress");
Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
}
}
本示例中,用到了 OnGestureListener 接口的 onScroll() 和 OnFling() 方法,涉及到了 Android 系统坐标及触摸 MotionEvent e1 和 e2、速度 velocityX、velocityY 等值,那么这里就顺便补充下 Android 屏幕坐标系:
(1)MotionEvent 中 e1 是手指第一次按上屏幕的起点,e2 是抬起手指离开屏幕的终点,Android 屏幕坐标系可知:
手指向右滑动,终点(e2)在起点(e1)的右侧,有 e2.getX() - e1.getX() 大于 0
手指向左滑动,终点(e2)在起点(e1)的左侧,有 e2.getX() - e1.getX() 小于 0
手指向下滑动,终点(e2)在起点(e1)的下侧,有 e2.getY() - e1.getY() 大于 0
手指向上滑动,终点(e2)在起点(e1)的上侧,有 e2.getY() - e1.getY() 小于 0
(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
distanceX,是前后两次 call 的 X 距离,不是 e2 与 e1 的水平距离
distanceX,是前后两次 call 的 Y 距离,不是 e2 与 e1 的垂直距离
(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
velocityX,是 X 轴的每秒速度
velocityY,是 Y 轴的每秒速度
具体数值的方向,仔细观察可以发现:velocityX、velocityY 的方向与 distanceX、distanceY 方向正好相反
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 8 个常用的 Android 开发工具
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论