分类: Android平台
2013-01-22 15:14:51
拖动消息响应
今天的第三篇博客,早整理过了,没发。呵呵,少废话,上文
拖动消息事件很常见,比如在windows上可以进行文件的打开,删除,复制等操作,在android可以创建应用程序的快捷方式,移动删除文件等操作。所以有必要学习一下这方面的知识。
实现的原始是在监听器OnTouchListener中对产生的触屏事件(MotionEvent对象)进行判断,分别进行不同的处理。
MotionEvent是用来记录移动事件的一个类。MotionEvent对象是与用户触摸相关的时间序列,该序列从用户首次触摸屏幕开始,经历手指在屏幕表面的任何移动,直到手指离开屏幕时结束。手指的初次触摸(ACTION_DOWN操作),滑动(ACTION_MOVE操作)和抬起(ACTION_UP)都会创建MotionEvent对象。移动过程中会产生大量事件,每个事件都会产生对应的MotionEvent对象记录发生的操作,触摸的位置,使用的多大压力,触摸的面积,合适发生,以及最初的ACTION_DOWN和时发生等相关的信息。
当用户触摸屏幕时将创建一个MotionEvent对象,如果把这个对象传递到程序中的合适的方法中,比如View对象的onTouchEvent()方法中。在这些方法中我们就可以分析MotionEvent对象的类型,来进行不同的操作。
这是我实现一个TextView的拖动效果的监听器部分的代码
private OnTouchListener tviewtouchevetn = new OnTouchListener(){
//定义一个事件监听器
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
lastX = event.getRawX();
lastY = event.getRawY()-50;
lastDownTime = event.getDownTime();
break;
case MotionEvent.ACTION_MOVE:
thisX = event.getRawX();
thisY = event.getRawY();
//判断是否是down后的较早的拖动
if(isfirstMove && Math.abs(thisX - lastX)>=10 && Math.abs(thisY - lastY)>=10) //消除抖动,和不经意的触碰
{
if (!mIsLongPressed) {
thisEventTime = event.getEventTime();
mIsLongPressed = isLongPressed(lastDownTime, thisEventTime, 100);
}
isfirstMove = false;
}
if (mIsLongPressed)
{ //拖动后的显示操作
mx = (int) (event.getRawX());
my = (int) (event.getRawY() - 50);
float leftedge = lastX - tv.getLeft();
float topedge = lastY - tv.getTop();
v.layout((int) (mx-leftedge),(int)(my-topedge),
(int)(mx+tv.getWidth()-leftedge),(int)(my+tv.getHeight()-topedge));
lastX = mx;
lastY = my;
//v.layout(mx - tv.getWidth() / 2, my - tv.getHeight()
// / 2, mx + tv.getWidth() / 2,
// my + tv.getHeight() / 2);
}
break;
case MotionEvent.ACTION_UP:
mIsLongPressed = false;
isfirstMove = true;
}
return true;
}
};
对上面的代码进行解释。
首先程序中界面只有一个TextView对象。当手指点击TextView时,这是MotionEvent.ACTION_DOWN 事件。这时获取按下的位置坐标(android设备屏幕上的坐标原点在左上角。向左为X轴正方向,向下为Y轴正方向)。其中lastY的值减去50是为了减去通知栏和标题栏。并且记录下现在的时间,主要是为了防止误操作,假滑动。
然后手指滑动的时候会产生MotionEvent.ACTION_MOVE ,在这里面也获取位置信息,然后进行比较(消抖处理),如果和之前存储的位置信息相差不大,即小于10,则说明是抖动,等待下次事件进行判断。因为手指在按住过程中是一直产生MotionEvent.ACTION_MOVE 事件的,所以可以一直判断即可,直到满足要求。isfirstMove 是用来判断是否是第一次产生滑动信息,因为在在滑动的开始时候会有抖动,在滑动过程中抖动可以忽略,所以就不需要再进行消抖动。
在消抖的时候还要对是否是假滑动进行判断,即手指擦屏幕这种假滑动。原理就是判断两次达到滑动事件持续的时间是否够长。如果不够长,就不会进行处理。当手指抬起的时候会产生MotionEvent.ACTION_UP ,这样这样再将两个boolean型的变量初始化,重新判断。
if (mIsLongPressed)
{ //拖动后的显示操作
mx = (int) (event.getRawX());
my = (int) (event.getRawY() - 50);
float leftedge = lastX - tv.getLeft();
float topedge = lastY - tv.getTop();
v.layout((int) (mx-leftedge),(int)(my-topedge),
(int)(mx+tv.getWidth()-leftedge),(int)(my+tv.getHeight()-topedge));
lastX = mx;
lastY = my;
//v.layout(mx - tv.getWidth() / 2, my - tv.getHeight()
// / 2, mx + tv.getWidth() / 2,
// my + tv.getHeight() / 2);
}
这段代码是滑动处理的关键代码。
其中v就是获得触摸事件的控件,即这里的TextView对象,在这里调用它的layout方法,来重新放置自己。该方法的四个参数是左上角和右下角的xy坐标。程序中传入的参数可以达到按下和拖动完成抬起时手指的位置在TextView上的位置不变。而注释掉的部分是当拖动完成手指抬起时,位置在TextView的中心位置。
另外需要说明的是:
在设置事件时我们有2中设置的方式,一种是委托式一种是回调式。第一种就是将事件的处理委托给监听器处理,你可以定义一个View.OnTouchListener接口的子类作为监听器,其中有onTouch()方法。而第二种是重写View类自己本身的onTouchEvent方法,也就是控件自己处理事件。onTouch方法接收一个MotionEvent参数和一个View参数,而onTouchEvent方法仅接收MotionEvent参数。这是因为监听器可以监听多个View控件的事件。无论是通过onTouchEvent还是onTouch方法 它们的返回值都是boolean类型。
true的含义是如果当前处理程序在处理完毕该事件后不希望传播给其他控件,则返回true。如果View对象不但对此事件不感兴趣,而且对与此触摸序列相关的任何未来事件都不感兴趣,那么返回false。比如如果Button的onTouchEvent方法想要处理用户的一次点击则会有2个事件产生ACTION_DOWN和ACTION_UP,按道理这两个事件都会调用onTouchEvent方法,如果方法返回false则在按下时你可以做一些操作,但是手指抬起时你将不能再接收到MotionEvent对象了,所以你也就无从处理抬起事件了