一.MotionEvent机制(触屏)
1.触屏操作的理解
最基本的操作类型:down : 手指按下
move : 手指在屏幕上移动
up : 手指从屏幕上离开
触屏操作的顺序:
down->move->move->…->up
2.相关API
1). MotionEvent : 触屏事件
int ACTION_DOWN=0 : 代表down
Int ACTION_MOVE=2 ; 代表move
Int ACTION_UP=1 : 代表up
getAction() : 得到事件类型值
getX() : 得到事件发生的x轴坐标(相对于当前视图)
getRawX() :得到事件发生的x轴坐标(相对于屏幕左顶点)
getY() : 得到事件发生的y轴坐标(相对于当前视图)
getRawY() :得到事件发生的y轴坐标(相对于屏幕左顶点)
2). Activity
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调
3). View
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调方法
void setOnTouchListener(OnTouchListener l) : 设置事件监听器
void setOnClickListener(OnClickListener l) : 设置点击监听
void setOnLongClickListener(OnLongClickListener l) : 设置长按监听
void setOnCreateContextMenuListener(OnCreateContextMenuListener l) : 用于创建菜单
4). ViewGroup
boolean dispatchTouchEvent(MotionEvent ev) : 分发事件
boolean onInterceptTouchEvent(MotionEvent ev) : 拦截事件的回调方法
3.触摸事件的分发与处理
事件产生的顺序为: down-->move-->move...--->up
事件对象被系统创建后, 首先会调用对应Activity对象的dispatchTouchEvent()进行分发
down在分发给视图对象的过程中要确定消费者(onTouchEvent()返回true),如果都返回false, 那事件的消费者只能是Activity了
后面的move和up事件, 将事件分发给消费者(可能是视图对象,也可能是Activity)处理, 如果视图不消费, 直接交给Activity处理消费
每个事件都需要有一个消费者
4.项目练习
1)功能描述:
2)技术点:通过手指移动来拖动图片
控制图片不能超出屏幕显示区域
MotionEvent处理对View进行动态定位(layout)
3).用到的View相关方法
int getLeft()
得到当前视图左顶点相对父视图的X轴坐标
int getTop()
得到当前视图左顶点相对父视图的Y轴坐标
int getRight()
得到当前视图右下角点相对父视图的X轴坐标
int getBottom()
得到当前视图右下角点相对父视图的Y轴坐标
layout(int left, int top, int right, int bottom) :
动态指定当前视图在父视图中的定位, 参数为相对父视图的坐标
ViewParent getParent() :
得到当前View的父视图对象
4).代码实现:
package com.example.event_06;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
public class MotionEventTestActivity extends Activity implements OnTouchListener {
private ImageView iv_touch;
private LinearLayout parentView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touch);
//得到MyImageView
iv_touch = (ImageView) findViewById(R.id.iv_touch);
parentView = (LinearLayout) iv_touch.getParent();
//设置touch监听
iv_touch.setOnTouchListener(this);
}
private int lastX;
private int lastY;
private int maxRight;
private int maxBottom;
@Override
public boolean onTouch(View v, MotionEvent event) {
//得到事件的坐标
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//得到父视图的right/bottom
if(maxBottom==0){//保证只赋一次值
maxRight = parentView.getRight();
maxBottom = parentView.getBottom();
}
//第一次记录lastX/lastY
lastX = eventX;
lastY = eventY;
break;
case MotionEvent.ACTION_MOVE:
//计算事件的偏移
int dx = eventX - lastX;
int dy = eventY - lastY;
//根据事件的偏移来移动imageView
int left = iv_touch.getLeft() + dx;
int right = iv_touch.getRight() + dx;
int bottom = iv_touch.getBottom() + dy;
int top = iv_touch.getTop() + dy;
//限制left >=0
if(left<0){
right -= left;
left = 0;
}
//限制top
if(top<0){
bottom -= top;
top = 0;
}
//限制right <=maxRight
if(right > maxRight){
left -= (right-maxRight);
right = maxRight;
}
//限制bottom <= maxBottom
if(bottom > maxBottom){
top -= bottom - maxBottom;
bottom = maxBottom;
}
iv_touch.layout(left, top, right, bottom);
//再次记录lastX/lastY
lastX = eventX;
lastY = eventY;
break;
default:
break;
}
return true;//所有的motionEvent都交给imageView处理
}
}
二,KeyEvent机制(按键)
1.相关API
KeyEvent
int ACTION_DOWN = 0 : 标识down的常量
int ACTION_UP = 1 : 标识up的常量
int getAction() : 得到事件类型
int getKeyCode() : 得到按键的keycode(唯一标识)
startTracking() : 追踪事件, 用于长按监听
Activity
boolean dispatchKeyEvent(KeyEvent event) : 分发事件
boolean onKeyDown(int keyCode, KeyEvent event) : 按下按键的回调
boolean onKeyUp(int keyCode, KeyEvent event) : 松开按键的回调
boolean onKeyLongPress(int keyCode, KeyEvent event) : 长按按键的回调
2.项目练习
功能描述:
第一次按back键, 只Toast提示, 不退出应用
2S内连按两次back键才退出应用
技术点:
KeyEvent处理
延迟消息的处理
代码实现:
package com.example.event_06;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.Toast;
public class KeyEventTestActivity extends Activity {
private boolean exit = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_key_event_test);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.e("TAG", "dispatchKeyEvent() keycode = " + event.getKeyCode() +"action = "+ event.getAction());
return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e("TAG", "onKeyDown() keycode = " + event.getKeyCode() +"action = "+ event.getAction());
//startTracking():追踪事件,用于长按监听
event.startTracking();
//return super.onKeyDown(keyCode, event);
return true;
}
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
if(msg.what==1){
exit = false;
}
};
};
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if(event.getKeyCode()==KeyEvent.KEYCODE_BACK){
if(!exit){
exit = true;
Toast.makeText(this , "再按一次就退出应用", 0).show();
//发消息延迟两秒将exit=false
handler.sendEmptyMessageDelayed(1, 2000);
return true;//不退出
}
}
return super.onKeyUp(keyCode, event);
}
}