事件处理
- 基于监听的事件处理
- 基于回调的事件处理
基于监听,绑定特有的事件监听器。
事件监听器 --> 事件源(按钮等组件) -->事件Event–>事件处理
基于回调的事件处理
- 重写组件的回调方法
- 重写Activity的回调方法
区别?
基于回调的事件处理用于通用事件的处理
基于监听的事件处理用于特定事件的处理
物理按键事件处理
- 音量键 KEYCODE_VOLUME_UP/DOWN
- 菜单键 KEYCODE_MENU
- 返回键 KEYCODE_BACK
- home键 KEYCODE_HOME
- 电源键 KEYCODE_POWER
android 为 物理按键定义三个状态
- 按下 onKeyDown
- 抬起 onKeyUp
- 长按 onKeyLongPress
例如:连续两次返回键,退出程序。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连续两次返回键退出程序"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.liyanfeng.eventtogo;
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;
@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();
return true;
}
return super.onKeyDown(keyCode, event);
}
public void exit() {
if (System.currentTimeMillis() - exitTime > 2000) {
Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
} else {
finish();
System.exit(0);
}
}
}
触摸屏事件
- 单击
- 长按
- 触摸
单击略过
长按 组件添加长按事件监听器 setOnLongClickListener()
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/long_click_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="长按弹出菜单" />
</LinearLayout>
package com.liyanfeng.eventtogo;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnLongClickListener {
private Button long_click_btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add("菜单A");
menu.add("菜单B");
}
private void initView() {
long_click_btn = (Button) findViewById(R.id.long_click_btn);
long_click_btn.setOnLongClickListener(this);
}
@Override
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.long_click_btn:
// 注册菜单
registerForContextMenu(v);
// 打开菜单
openContextMenu(v);
break;
}
return false;
}
}
触摸事件监听器 setOnTouchListener()
自定义个View 来画一个BitMao
package com.liyanfeng.chumoshijian;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Build;
import android.view.View;
import androidx.annotation.RequiresApi;
public class MoveItem extends View {
public float bitMapX;
public float bitMapY;
public MoveItem(Context context) {
//
super(context);
bitMapX = 65;
bitMapY = 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//定义画笔
@SuppressLint("DrawAllocation") Paint paint = new Paint();
// 定义图像来源
@SuppressLint("DrawAllocation") Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.t1);
//在画布上绘制图像
bitmap = setScale(bitmap, 160, 160);
canvas.drawBitmap(bitmap, bitMapX, bitMapY, paint);
// 回收图像资源
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
}
// 更改尺寸
public Bitmap setScale(Bitmap bitmap, int dst_width, int dst_height) {
int src_width = bitmap.getWidth();
int src_height = bitmap.getHeight();
float scale_width = ((float) dst_width) / src_width;
float scale_height = ((float) dst_height) / src_height;
Matrix matrix = new Matrix();
matrix.postScale(scale_width, scale_height);
Bitmap dst_bitmap = Bitmap.createBitmap(bitmap, 0, 0, src_width, src_height, matrix, true);
return dst_bitmap;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/relativelayout"
tools:context=".MainActivity">
</RelativeLayout>
MainJava
package com.liyanfeng.chumoshijian;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity {
private MoveItem moveItem;
private RelativeLayout ll;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
makeMoveItem();
}
private void initView() {
ll = (RelativeLayout) findViewById(R.id.relativelayout);
moveItem = new MoveItem(this);
}
@SuppressLint("ClickableViewAccessibility")
private void makeMoveItem() {
moveItem = new MoveItem(this);
// 添加触摸事件
moveItem.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 当手指触摸的时候,更改位图的坐标位置
moveItem.bitMapX = event.getX() - 80;
moveItem.bitMapY = event.getY() - 80;
moveItem.invalidate();// 重新绘制
return true;
}
});
ll.addView(moveItem);
}
}
单击事件和触摸事件
单击事件和触摸事件可能会发生冲突,两者中,触摸事件先行,当onTouch返回true,意味着触摸事件将本次事件消费完成,那么不会触发单击事件,如果返回false,会交给单击事件处理
手势检测
GestureDetector类 手势检测器
GestureDetector.OnGestureListener 实例
需要重写
- onDown 触摸按下
- onFling 手指拖过
- onLongPress 手指长按
- onScroll
- onShowPress
- onSingleTapUp 轻击
实现滑动相册
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
tools:context=".MainActivity">
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
package com.liyanfeng.huadongxiangce2;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
private Animation[] animations = new Animation[4]; //动画数组
final int distance = 50; // 记录手势动作开始结束两点之间的最小距离
private int[] images = new int[]{
R.drawable.img1,
R.drawable.img2,
R.drawable.img3,
R.drawable.img4
};
private ViewFlipper view_flipper;
GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
makeViewFlipper();
}
private void initView() {
gestureDetector = new GestureDetector(this, this);
view_flipper = (ViewFlipper) findViewById(R.id.view_flipper);
}
private void makeViewFlipper() {
for (int i = 0; i < images.length; i++) {
ImageView iv = new ImageView(this);
iv.setImageResource(images[i]);
view_flipper.addView(iv);
}
// 初始化动画数组
animations[0] = AnimationUtils.loadAnimation(this,R.anim.slide_in_from_left);
animations[1] = AnimationUtils.loadAnimation(this,R.anim.slide_out_to_left);
animations[2] = AnimationUtils.loadAnimation(this,R.anim.slide_in_from_right);
animations[3] = AnimationUtils.loadAnimation(this,R.anim.slide_out_to_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 中的坐标判断滑动方向
if (e1.getX()-e2.getX()>distance){
// 点1比点2大 从右向左滑动
view_flipper.setInAnimation(animations[2]);
view_flipper.setOutAnimation(animations[1]);
view_flipper.showPrevious();
return true;
}else if (e2.getX()-e1.getX()>distance){
//从左向右滑
view_flipper.setInAnimation(animations[0]);
view_flipper.setOutAnimation(animations[3]);
view_flipper.showNext();
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 将屏幕的手势处理交给gestureDetector
return gestureDetector.onTouchEvent(event);
}
}
手势添加
创建手势 安卓模拟器的 Gestures Builder app
手势组件
<android.gesture.GestureOverlayView></android.gesture.GestureOverlayView>
- gestureStrokeType 启动多笔绘制属性
Activity 实现 GestrueOverlayView.OnGesturePerformedListener接口
在res 创建 raw 文件夹用来存放从模拟器导出的手势文件gestures
创建 GestuerLibrary 来加载手势文件 gesturelibrary.fromRawResourse(this,R.raw.gestures)
gesturelibrary.load()
判断是否加载失败
对GestureOverlayView组件设置监听器和属性设置
gestureOverlayView.setGestureColor(Color.BLACK) 设置手势颜色
gestureOverlayView.setFadeOffset(1000) 手势淡出事件
gestureOverlayView.addOnGesturePerformedListener(this)添加监听器
根据评分 找到最合适的结果
public void onGesturePerformed(GestureOverlayView v,Gesture gesture){
ArrayList<Prediction> gestures = =gestureLibrary.recognize(gesture);
int idx = 0;
double score = 0.0;
for(int i,i<gestures.size(),i++){
Prediction res = gestures.get(i)
if(res>score){
idx = i;
score=res.score;
}
}
Log.i("最佳结果为",gestures.get(idx).name)
}