1 概述
物理按键事件:按下,抬起和长按。 触摸事件:按下,抬起,滑动和双击。
1.1 基于监听的事件处理(setOnTouchListener())
做法是绑定特定的事件监听器
1.2 基于回调的事件处理(onTouchEvent())
做法是重写回调方法。View类事件处理的回调方法如下:
方法 | 说明 | onKeyDown() | 按下按键 | okKeyLongPress() | 长按 | onKeyShortCut() | 按下键盘快捷键 | onKeyUp() | 松开按键 | onTouchEvent() | 触摸 |
表9-1 View类事件处理的回调方法 对于某些事件,无法采用基于回调的事件处理方式处理,只能采用基于监听的事件处理方式。
2 使用物理按键事件实现连续两次按下"返回键"退出
物理按键 | KeyEvent | 电源键 | KEYCODE_POWER | 返回键 | KEYCODE_BACK | 菜单键 | KEYCODE_MENU | Home键 | KEYCODE_HOME | 查找键 | KEYCODE_SEARCH | 音量键 | KEYCODE_VOLUME_UP KEYCODE_VOLUME_DOWN | 方向键 | KEYCODE_DPAD_CENTER KEYCODE_DPAD_UP KEYCODE_DPAD_DOWN KEYCODE_DPAD_LEFT KEYCODE_DPAD_RIGHT |
表9-2 Android设备可用物理按键 KeyDown: MainActivity.java
public class MainActivity extends AppCompatActivity {
private long exitTime = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
exit();
Log.d("MainActivity","return false");
return false;
}
return super.onKeyDown(keyCode, event);
}
public void exit() {
// 计算按键时间差是否大于两秒
if ((System.currentTimeMillis() - exitTime) > 2000) {
Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
} else {
// 连续按键两次退出
finish();
System.exit(0);
}
}
}
https://github.com/hanyuhang-hz/android-demos
3 使用触摸屏事件实现长按图片收藏,移动帽子
触摸屏事件: 单击事件:setOnClickListener() 长按事件:setOnLongClickListener() 触摸事件:setOnTouchListener()
LongClick: MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
registerForContextMenu(v); // 将长按事件注册菜单中
openContextMenu(v); // 打开菜单
// 表示用户消耗此事件,现象为收藏菜单显示后一直存在
return true;
// 表示系统消耗此事件,现象为收藏菜单显示后立刻消失
// return false;
}
});
}
// 创建菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add("收藏");
}
}
https://github.com/hanyuhang-hz/android-demos
MoveHat MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
final HatView hat = new HatView(MainActivity.this); // 创建并实例化HatView类
hat.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
hat.bitmapX = event.getX()-10; // 设置帽子显示位置的X坐标
hat.bitmapY = event.getY()-50; // 设置帽子显示位置的Y坐标
hat.invalidate(); // 重绘hat组件
return true;
}
});
relativeLayout.addView(hat);
}
}
当触摸事件onTouch发生后,会产生一个MotionEvent事件对象,可以通过该对象获取当前的x和y坐标。 HatView.java
public class HatView extends View {
public float bitmapX; // 帽子显示位置的X坐标
public float bitmapY; // 帽子显示位置的Y坐标
public HatView(Context context) {
super(context);
bitmapX = 30;
bitmapY = 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.hat);
Log.d("HatView", "bitmapX: " + bitmapX + " bitmapY: " + bitmapY);
// 绘制帽子
canvas.drawBitmap(bitmap, bitmapX, bitmapY, paint);
if (bitmap.isRecycled()) {
bitmap.recycle(); // 强制回收图片
}
}
}
https://github.com/hanyuhang-hz/android-demos
4 区分触摸事件和单击事件
在Android中,一次用户操作可以被不同的View按次序分别处理,我们将响应了用户的一次UI操作称之为消耗了该事件。对于一个View组件,Android如何区分触摸事件和单击事件呢? TouchAndClick MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MainActivity","onClick 单击事件");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_DOWN){
Log.i("MainActivity","onTouch 按下");
}else if (event.getAction()==MotionEvent.ACTION_UP){
Log.i("MainActivity","onTouch 抬起");
}
return false; // 表示未消耗掉这个事件
//return true; // 表示消耗掉这个事件
}
});
}
}
未消耗掉这个事件时,单击事件可以获取到,触摸事件优先级高于单击事件:
?消耗掉这个事件时,单击事件不能获取到:
?https://github.com/hanyuhang-hz/android-demos
|