目录
6.Android事件处理和手势(一)
1.事件处理概述
1-1.基于监听的事件处理
1-2.基于回调的事件处理
2.物理按键事件处理
3.触摸屏事件处理
3-1.单击事件
3-2.长按事件
3-3.触摸事件
6.Android事件处理和手势(一)
1.事件处理概述
现在的图形界面应用程序都是通过事件来实现人机交互的。事件就是用户对图形界面的操作。在Android手机和平板电脑上,主要包括物理按键事件和触摸屏事件两大类。物理按键事件包括按下、抬起和长按等;触摸屏事件包括按下、拾起、滑动和双击等。
在Android组件中提供了事件处理的相关方法。例如,在View类中提供了onTouchEvent() 方法,可以重写该方法来处理触摸屏事件,这种方式主要适用于重写组件的场景,但是仅仅通过重写这个方法来完成事件处理是不够的。为此,Android 提供了使用setOnTouchListener()方法为组件设置监听器来处理触摸屏事件,这在日常开发中更加常用。
在Android中提供了两种方式的事件处理,一种是基于监听的事件处理,另一种是基于回调的事件处理。
1-1.基于监听的事件处理
实现基于监听的事件处理,主要做法就是为Android的UI组件绑定特定的事件监听器。在事件监听的处理模型中,主要有以下3类对象:
◆Event Source (事件源) :即产生事件的来源,通常是各种组件,例如,按钮、窗口和菜单等。
◆Event(事件):事件中封装了UI组件上发生的特定事件的具体信息,如果监听器需要获取UI组件上所发生事件的相关信息,一 般通过Event对象来传递。
◆Event Listener (事件监听器) :监听事件源所发生的事件,并对不同的事件做出相应的响应。
1-2.基于回调的事件处理
实现基于回调的事件处理,主要做法就是重写Android组件特定的回调方法,或者重写Activity组件的回调方法。从代码实现的角度看,基于回调的事件处理模型更加简单。为了使用回调机制来处理GUI组件(图形用户界面)上所发生的事件,需要为该组件提供对应的事件处理方法,可以通过继承GUI组件类,并重写该类的事件处理方法来实现。
为了实现回调机制的事件处理,Android为所有GUI组件都提供了一些事件处理的回调方法, 例如,在View类中就包含了一些事件处理的回调方法,这些方法如表6.1所示。
表6.1 View类中事件处理的回调方法
方法 |
说明 |
boolean onKeyDown(int keyCode, KeyEvent event) |
当用户在该组件上按下某个按键时触发 |
bolean onKeyLongPress(int keyCode, KeyEvent event) |
当用户在该组件上长按某个按键时触发 |
boolean onKeyShortcut(int keyCode, KeyEvent event) |
当一个键盘快捷键事件发生时触发 |
boolean onKeyUp(int keyCode, KeyEvent event) |
当用户在该组件上松开某个按键时触发 |
boolean onTouchEvent (MotionEvent event) |
当用户在该组件上触发触摸屏事件时触发 |
boolean onTrackballEvent(MotionEvent event) |
当用户在该组件上触发轨迹球事件时触发 |
一般来说,基于回调的事件处理方式可用于处理一些通用性的事件,事件处理的代码会比较简洁。但对于某些特定的事件,无法采用基于回调的事件处理方式实现时,就只能采用基于监听的事件处理方式了。
2.物理按键事件处理
一个标准的 Android设备包含了多个能够触发事件的物理按键。
Android设备常用物理按键能够触发的事件及其说明如表6.2所示。
表6.2 Android 设备可用物理按键及其触发事件
物理按键 |
KeyEvent |
说明 |
音量键 |
KEYCODE_VOLUME_UP KEYCODE_VOLUME_DOWN |
控制当前上下文音量,如音乐播放器、手机铃声、通话音量等 |
返回键 |
KEYCODE_ BACK |
返回到前一个界面 |
菜单键 |
KEYCODE_MENU |
显示当前应用的可用菜单 |
在Android中处理物理按键事件时,常用的回调方法有以下3个:
◆onKeyUp():当用户松开某个按键时触发该方法。
◆onKeyDown():当用户按下(未松开)某个按键时触发该方法。
◆onKeyLongPress():当用户长按某个按键时触发该方法。
例:
![](https://img-blog.csdnimg.cn/dc9c80aeddc3483e841047144d0edc92.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdHR5Y3I=,size_16,color_FFFFFF,t_70,g_se,x_16)
MainActivity.java
package com.example.exitmapapplication;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private long exitTime = 0;//退出时间变量值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getSupportActionBar();
actionBar.hide();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
//判断是否单击了返回按钮
if(keyCode==KeyEvent.KEYCODE_BACK){
exit();//创建并调用退出方法
return true;//拦截返回键
}
return super.onKeyDown(keyCode, event);
}
private void exit() {
if((System.currentTimeMillis() - exitTime)>2000){//计算按键时间差是否大于两秒
Toast.makeText(getApplicationContext(),"再按一次退出程序",Toast.LENGTH_SHORT).show();
exitTime=System.currentTimeMillis();
}else {
finish();
System.exit(0);//销毁强制退出
}
}
}
3.触摸屏事件处理
当下,主流的Android手机、平板电脑都以较大的屏幕取代了外置键盘,很多操作都是通过触摸屏幕来实现的。其中,常用的触摸屏事件主要包括单击事件、 长按事件和触摸事件等。
3-1.单击事件
在手机应用中,经常需要实现在屏幕中单击某个按钮或组件执行一些操作。这时就可以通过单击事件来完成。在处理单击事件时,可以通过为组件添加单击事件监听器的方法来实现。Android为组件提供了setOnClickListener()方法,用于为组件设置单击事件监听器。该方法的参数是一个View.OnClickListener接口的实现类对象。View.OnClickListener 接口的定义如下:
public static interface View.OnClickListener{
public void onClick(View v);
}
从上面接口的定义中可以看出,在实现View.OnClickListener接口时,需要重写onClick()方法。当单击事件触发后,将调用onClick()方法执行具体的事件处理操作。
例如,要为名称为“button1”的按钮添加一个单击事件监听器,并且实现在单击该按钮时弹出消息提示框显示“单击了按钮”,可以通过下面的代码实现:
Button button1=new Button(this);
button1.setOnClicklistener(new View.OnClicklistener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"单击了按钮",Toast.LENGTH_SHORT).show();
}
});
3-2.长按事件
在Android中还提供了长按事件的处理操作,长按事件与单击事件不同,该事件需要长按某一个组件2秒之后才会触发。在处理长按事件时,可以通过为组件添加长按事件监听器的方法来实现。
Android 为组件提供了setOnLongClickListener()方法,用于为组件设置长按事件监听器。该方法的参数是一个View.OnLongClickListener接口的实现类对象。View.OnLongClickListener 接口的定义如下:
public static interface View.OnLongClickListener{
public boolean onLongClick(View v);
}
从上面接口的定义中可以看出,在实现View.OnLongClickListener 接口时,需要重写onLongClick()方法,当长按事件触发后,将调用onLongClick()方法执行具体的事件处理操作。
例:
![](https://img-blog.csdnimg.cn/277a56d53e474438a9b7df104f81bb9f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdHR5Y3I=,size_16,color_FFFFFF,t_70,g_se,x_16)
MainActivity.java
package com.example.longpressevent;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getSupportActionBar();
actionBar.hide();
ImageView imageView = (ImageView) findViewById(R.id.main_iv2);//获取图片组件
//创建长按监听事件
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
registerForContextMenu(view);//将长按事件注册到菜单中
openContextMenu(view);//打开菜单
return true;
}
});
}
@Override
public void onCreateContextMenu(ContextMenu menu,View v,
ContextMenu.ContextMenuInfo menuInfo){//创建菜单
super.onCreateContextMenu(menu,v,menuInfo);
//为菜单添加参数
menu.add("收藏");
menu.add("举报");
}
}
在AndroidManifest.xml文件中修改<application>标记的android:theme属性:
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
3-3.触摸事件
触摸事件就是指当用户触摸屏幕之后产生的一种事件,当用户在屏幕上划过时,可以通过触摸事件获取用户当前的坐标。在处理触摸事件时,可以通过为组件添加触摸事件监听器的方法来实现。
Android为组件提供了setOnTouchListener()方法,用于为组件设置触摸事件监听器。该方法的参数是一个 View.OnTouchListener接口的实现类对象。View.OnTouchListener 接口的定义如下:
public interface View.OnTouchListener{
public abstract boolean onTouch(View v, MotionEvent event);
}
从上面接口的定义中可以看出,在实现View.OnTouchListener接口时需要重写onTouch(方法。当触摸事件触发后,将调用onTouch()方法执行具体的事件处理操作,同时会产生一个MotionEvent事件类的对象,通过该对象可以获取用户当前的X坐标和Y坐标。
例:
![](https://img-blog.csdnimg.cn/009d865ed2e64bd1b29456372b0cdeb3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdHR5Y3I=,size_15,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/bce5d356f492465e8d032a8487078c33.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdHR5Y3I=,size_16,color_FFFFFF,t_70,g_se,x_16)
MainActivity.java
package com.example.touchevents;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getSupportActionBar();
actionBar.hide();
//获取相对布局管理器
RelativeLayout relativeLayout=(RelativeLayout) findViewById(R.id.qie);
final HatView hat = new HatView(MainActivity.this);//创建并实例化HatView类
//为帽子添加触摸事件监听器
hat.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
hat.bitmapY=motionEvent.getX()-80;//设置帽子显示位置的X坐标
hat.bitmapY=motionEvent.getY()-50;//设置帽子显示位置的Y坐标
hat.invalidate();//重绘hat组件
return true;
}
});
relativeLayout.addView(hat);//将hat添加到布局管理器中
}
}
HatView.java
package com.example.touchevents;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class HatView extends View {
public float bitmapX;//帽子显示位置的X坐标
public float bitmapY;//帽子显示位置的Y坐标
public HatView(Context context) {//重写构造方法
super(context);
bitmapX=295;//帽子默认显示位置的X坐标
bitmapY=0;//帽子默认显示位置的Y坐标
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint paint=new Paint();//创建Paint对象
//根据图片生成位图对象
Bitmap bitmap= BitmapFactory.decodeResource(this.getResources(),R.drawable.hat);
canvas.drawBitmap(bitmap,bitmapX,bitmapY,paint);//绘制帽子
if(bitmap.isRecycled()) {//判断图片是否回收
bitmap.recycle();//强制回收图片
}
}
}