基于回调机制的事件处理
onKeyDown()方法:当手机上的物理按键被按下时会回调此方法
onKeyUp()方法:当手机上的按下物理按键抬起时会回调此方法
onTouchEvent()方法:触摸屏幕回调方法
onFocusChanged()方法:View控件焦点改变时回调此方法(书p208)
演示
/*
物理按键被按下
@param keyCode 被按下的物理按键ID
@param event 按键事件的对象,包含事件的详细信息
@return 返回为true表示已经完整的处理事件,并不希望其他的回调方法进行处理。
返回为false表示并没有完全处理事件,更希望其他回调方法再次进行处理。
*/
private boolean flag = true;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Toast.makeText(this, "物理按键被按下", Toast.LENGTH_SHORT).show();
if (keyCode == KeyEvent.KEYCODE_BACK) {
Toast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show();
if (flag) {
flag = false;
return true;//屏蔽后退按键
}
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Toast.makeText(this, "物理按键被抬起", Toast.LENGTH_SHORT).show();
return super.onKeyUp(keyCode, event);
}
/*
触摸事件
@param event
@return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
flag = true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Toast.makeText(this, "按下", Toast.LENGTH_SHORT).show();
break;
case MotionEvent.ACTION_UP:
Toast.makeText(this, "抬起", Toast.LENGTH_SHORT).show();
break;
case MotionEvent.ACTION_MOVE:
Toast.makeText(this, "滑动", Toast.LENGTH_SHORT).show();
break;
}
return super.onTouchEvent(event);
}
物理按键
常用的物理按键方法
onKeyDown():按下操作
onKeyUp():抬起操作
onKeyLongPress():长按操作
案例连按两次返回键退出应用
@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(this, "再按一次退出程序", Toast.LENGTH_SHORT).show();
exitTime=System.currentTimeMillis();
}else {
finish();
System.exit(0);
}
}
常用的物理按键
音量+:KEYCODE_VOLUME_UP
音量-:KEYCODE_VOLUME_DOWN
电源键:KEYCODE_POWER
菜单键:KEYCODE_MENU
主屏键:KEYCODE_HOME
返回键:KEYCODE_BACK
基于监听的事件处理
长按事件处理
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//注册到菜单中
registerForContextMenu(v);
//打开菜单框
openContextMenu(v);
//要返回true才会弹出,否则只会闪一下
return true;
}
});
//菜单项方法
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add("收藏");
menu.add("举报");
}
焦点改变事件处理
iv1 =findViewById(R.id.iv1);
iv2 =findViewById(R.id.iv2);
iv1.setOnFocusChangeListener(this);
iv2.setOnFocusChangeListener(this);
/*
检测控件是否获得焦点
@param v 表示触发焦点发生改变的事件源
@param hasFocus 是否获得焦点
*/
@Override
public void onFocusChange(View v, boolean hasFocus) {
switch (v.getId()){
case R.id.iv1:
tv.setText("您选择了滑稽");
break;
case R.id.iv2:
tv.setText("您选择了郭韬");
break;
}
}
键盘监听事件处理
iv1.setOnKeyListener(this);
iv2.setOnKeyListener(this);
/*
键盘监听事件处理
@param v 表示事件源
@param keyCode 键盘的键盘码
@param event 键盘事件封装对象,包含事件详细信息,发生的事件、事件类型等信息
@return
*/
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
switch (keyCode){
case KeyEvent.KEYCODE_A: //键盘上的A
iv1.performClick();//模拟按钮单击
iv1.requestFocus();//使按钮1获得焦点
break;
case KeyEvent.KEYCODE_B: //键盘上的B
iv2.performClick();//模拟按钮单击
iv2.requestFocus();//使按钮2获得焦点
break;
}
return false;
}
触摸事件监听
iv1.setOnTouchListener(this);
iv2.setOnTouchListener(this);
/*
触摸事件
@param v 被触摸的对象
@param event 触摸事件封装类
@return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()){
case R.id.iv1:
Toast.makeText(this, "滑稽被摸了", Toast.LENGTH_SHORT).show();
break;
case R.id.iv2:
Toast.makeText(this, "郭韬被摸了", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
案例——触摸改变控件位置
package com.example.touch;
public class Funny extends View {
public float funnyX;
public float funnyY;
public Funny(Context context) {
super(context);
funnyX=0;
funnyY=0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画笔
Paint paint =new Paint();
//
Bitmap bitmap= BitmapFactory.decodeResource(this.getResources(),R.drawable.funny);
//绘制滑稽
canvas.drawBitmap(bitmap,funnyX,funnyY,paint);
//如果没有回收强制回收图片
if(bitmap.isRecycled()){
bitmap.recycle();
}
}
}
package com.example.touch;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建滑稽对象
final Funny funny=new Funny(this);
//添加触摸事件
funny.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//触摸的时候根据手指重新定义滑稽坐标
funny.funnyX=event.getX()-funny.getWidth()/5;
funny.funnyY=event.getY()-funny.getHeight()/5;
//重绘制滑稽
funny.invalidate();
return true;
}
});
//将滑稽添加到布局管理器中
RelativeLayout relativeLayout=findViewById(R.id.rl);
relativeLayout.addView(funny);
}
}
触摸
OnGestureListener接口
package com.example.mygesture;
//第一步:实现GestureDetector.OnGestureListener接口实现所有方法
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
Animation[] animations=new Animation[4];
final int distance=50;
private int[] images=new int[]{
R.drawable.drink1,R.drawable.drink2,R.drawable.drink3,R.drawable.drink4,R.drawable.drink5,R.drawable.drink6};
private ViewFlipper flipper;
//第二步:定义一个全局的手势检测器
GestureDetector detector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
detector=new GestureDetector(MainActivity.this,this);
//第三步:将要显示的图片加载到ViewFlipper中,并且初始化动画数组
flipper=findViewById(R.id.flipper);
for(int i=0;i<images.length;i++){
ImageView imageView=new ImageView(MainActivity.this);
imageView.setImageResource(images[i]);
flipper.addView(imageView);
}
animations[0]= AnimationUtils.loadAnimation(this,R.anim.slide_in_left);//左进
animations[1]= AnimationUtils.loadAnimation(this,R.anim.slide_out_left);//左出
animations[2]= AnimationUtils.loadAnimation(this,R.anim.slide_in_right);//右进
animations[3]= AnimationUtils.loadAnimation(this,R.anim.slide_out_right);//右出
}
//触摸事件按下时触发
@Override
public boolean onDown(MotionEvent e) {
return false;
}
//用户按下未移动
@Override
public void onShowPress(MotionEvent e) {
}
//用户轻击时触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
//移动时触发?
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
//用户长按时触发
@Override
public void onLongPress(MotionEvent e) {
}
//用户拖动时触发
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//第四步:在onFling()方法中通过触摸事件的X坐标判断是向左滑动还是向右滑动
if(e1.getX()-e2.getX()>distance){
//从右向左滑动
flipper.setInAnimation(animations[2]);//右进
flipper.setOutAnimation(animations[1]);//左出
//显示前一张图片
flipper.showPrevious();
return true;
}else if(e2.getX()-e1.getX()>distance){
//从左向右滑动
flipper.setInAnimation(animations[0]);//左进
flipper.setOutAnimation(animations[3]);//右出
//显示下一张图片
flipper.showNext();
return true;
}
return false;
}
//第五步:将Activity上的触摸事件交给GestureDetector处理
@Override
public boolean onTouchEvent(MotionEvent event) {
// return super.onTouchEvent(event);
return detector.onTouchEvent(event);
}
}
OnDoubleTapListener接口
需要配合GestureDetector.OnGestureListener使用
//当用户单击屏幕时会触发此方法
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Toast.makeText(this, "单击", Toast.LENGTH_SHORT).show();
return false;
}
//当用户双击屏幕时会触发此方法
@Override
public boolean onDoubleTap(MotionEvent e) {
Toast.makeText(this, "双击", Toast.LENGTH_SHORT).show();
return false;
}
//双击以后的输入事件都会会触发此方法
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
Toast.makeText(this, "双击后触发的方法", Toast.LENGTH_SHORT).show();
return false;
}
手势的创建
1.交互界面代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="请在屏幕下方绘制手势"/>
<android.gesture.GestureOverlayView
android:id="@+id/gesture"
android:layout_width="match_parent"
android:layout_height="match_parent"
//设置为多笔绘制
android:gestureStrokeType="multiple"/>
</RelativeLayout>
2.对话框界面代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="请输入手势名称"
android:textSize="18dp"/>
<EditText
android:id="@+id/gesture_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tv_add"/>
<ImageView
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/gesture_name"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
3.java控制代码
package com.example.mygesture;
public class MainActivity2 extends AppCompatActivity {
private EditText gestureName;
private GestureOverlayView gestureView;
private Gesture mGesture;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2);
initView();
}
private void initView() {
//获取手势编辑视图
gestureView = (GestureOverlayView) findViewById(R.id.gesture);
gestureView.setGestureColor(Color.BLUE);//设置手势绘制颜色
gestureView.setGestureStrokeWidth(10);//设置手势绘制的宽度
//为手势完成事件绑定事件监听器,手势完成后,触发该事件
gestureView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
mGesture=gesture;
//加载save_gesture.xml界面布局视图
View dialog=getLayoutInflater().inflate(R.layout.save_gesture,null);
ImageView imageView=dialog.findViewById(R.id.show);
gestureName=dialog.findViewById(R.id.gesture_name);
//根据Gesture包含的手势创建一个位图
Bitmap bitmap=gesture.toBitmap(128,128,10,0xff0000ff);
imageView.setImageBitmap(bitmap);
//使用对话框显示dialog组件
new AlertDialog.Builder(MainActivity2.this)
.setView(dialog)
.setPositiveButton("保存", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity2.this,new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}
})
.setNegativeButton("取消",null).show();
}
});
}
public void saveFile(){
if(mGesture!=null){
//获取指定文件对应手势库
GestureLibrary lib= GestureLibraries.fromFile("/sdcard/mygestures");
lib.addGesture(gestureName.getText().toString(),mGesture);
boolean result=lib.save();//保存手势库
if(result) Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
else Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==1){
for(int i=0;i<permissions.length;i++){
if(grantResults[i]== PackageManager.PERMISSION_GRANTED){
saveFile();
}else{
Toast.makeText(this, "权限"+permissions[i]+"申请失败,不能保存手势库文件", Toast.LENGTH_SHORT).show();
}
}
}
}
}
手势识别
0.创建raw文件夹将手势库文件放进去
1.布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/editText"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
/>
<android.gesture.GestureOverlayView
android:id="@+id/gov"
android:layout_width="320dp"
android:layout_height="300dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="100dp"
android:gestureStrokeType="multiple"
android:background="#000"/>
</RelativeLayout>
2.java控制代码
package com.example.mygesture;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.Prediction;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.EditText;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
//第二步:让Activity实现GestureOverlayView.OnGesturePerformedListener接口,重写onGesturePerformed方法
public class MainActivity3 extends AppCompatActivity implements GestureOverlayView.OnGesturePerformedListener {
private GestureLibrary library;
private EditText editText;
private GestureOverlayView gov;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
initView();
}
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
//第五步:获取最佳匹配进行显示,并更新编辑框
//获得全部预测结果
ArrayList<Prediction> gestures=library.recognize(gesture);
int index=0;//预测对象
double score=0.0;//预测得分
for(int i=0;i<gestures.size();i++){
Prediction result=gestures.get(i);
if(result.score>score){
index=i;
score=result.score;
}
}
String text=editText.getText().toString();
text+=gestures.get(index).name;
editText.setText(text);
}
private void initView() {
//第三步:加载raw文件中的手势文件,如果加载失败退出应用
library= GestureLibraries.fromRawResource(MainActivity3.this,R.raw.mygestures);
//判断加载是否成功
if(!library.load()){
finish();
}
//第四步:获得GestureOverlayView组件,并且为其设置属性和事件监听
editText = (EditText) findViewById(R.id.editText);
gov = (GestureOverlayView) findViewById(R.id.gov);
gov.setGestureColor(Color.YELLOW);//颜色
gov.setGestureStrokeWidth(10);//宽度
gov.setFadeOffset(2000);//设置间隔为2秒
//事件监听
gov.addOnGesturePerformedListener(this);
}
}