相关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) : 拦截事件的回调方法
触摸事件的分发与处理
事件产生的顺序为: down–>move–>move…—>up
事件对象被系统创建后, 首先会调用对应Activity对象的dispatchTouchEvent()进行分发
down在分发给视图对象的过程中要确定消费者(onTouchEvent()返回true),如果都返回false, 那事件的消费者只能是Activity了
后面的move和up事件, 将事件分发给消费者(可能是视图对象,也可能是Activity)处理, 如果视图不消费, 直接交给Activity处理消费
每个事件都需要有一个消费者
案例图片移动
用到的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的父视图对象
布局很简单
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/image"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/logo"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
移动imageview并设置拖动范围
private ImageView iv_main;
private RelativeLayout parentView;
private int maxRight;
private int maxBottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_main = (ImageView) findViewById(R.id.image);
//获取父布局
parentView = (RelativeLayout) iv_main.getParent();
iv_main.setOnTouchListener(this);
}
private int lastX;
private int lastY;
@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:
//第一次记录lastX,lastY
lastX = eventX;
lastY = eventY;
break;
case MotionEvent.ACTION_MOVE:
if (maxRight == 0) {
maxRight = parentView.getRight();
maxBottom = parentView.getBottom();
}
//计算事件的偏移
int dx = eventX - lastX;
int dy = eventY - lastY;
//根据事件偏移量来移动ImageView
int left = iv_main.getLeft() + dx;
int right = iv_main.getRight() + dx;
int top = iv_main.getTop() + dy;
int bottom = iv_main.getBottom() + dy;
//限制left
if (left < 0) {
right += -left;
left = 0;
}
//限制top
if (top < 0) {
bottom += -top;
top = 0;
}
//限制right
if (right > maxRight) {
left -= right - maxRight;
right = maxRight;
}
//限制bottom
if (bottom > maxBottom) {
top -= bottom - maxBottom;
bottom = maxBottom;
}
iv_main.layout(left, top, right, bottom);
lastY = eventY;
lastX = eventX;
break;
}
return true;//事件被消费,由子view处理
}
}
按键的操作
理解
操作的基本类型
down : 手指按下;
up : 手指从按键上离开
按键操作的顺序: downdowndown…—>up
对按键的任何一个操作, 系统都会创建一个KeyEvent对象来对应这个操作
按键的长按监听: down之后一定时间还没有up时会触发长按监听回调
相关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) : 长按按键的回调
案例:点击返回键两秒后退出程序
//是否离开
private boolean isExit = false;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
isExit=false;
}
super.handleMessage(msg);
}
};
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (!isExit) {//不离开
isExit = true;
Toast.makeText(this, "再点击一次退出程序", Toast.LENGTH_SHORT).show();
handler.sendEmptyMessageDelayed(1, 2000);//两秒后执行
return true;
}
return super.onKeyUp(keyCode, event);
}