手势其实是一个比较复杂的东西,首先是因为处理的时机。Android中触摸屏的事件其实只有ACTION_DOWN、ACTION_MOVE和 ACTION_UP这三种,当然我们实现手势的逻辑时,一般会用到GestureDetector,它有许多封装好的事件回调接口,比如onFling、 onLongPress、onScroll等,其实这些事件只是对上面那三个基本时间的包装而已:即三个基本事件按一定的序列出现,则会触发响应的 GestureDetector中的事件,比如ACTION_DOWN 加上三个ACTION_MOVE再加上ACTION_UP就是一次Fling事件等等。
虽然手势能给用户带来比较新奇好玩的体验,GestureDetector这样的接口很容易理解,但是却也有很多问题,主要是自定义手势时。假如我们要实现一个自定义的手势,即当用户在触摸屏上画圆时响应我们的事件处理逻辑,那么当用户画圆时,其实也是一个Scroll事件,这时候就不太好确定到底响应画圆事件还是Scroll事件了。
手势带来的另一个问题是UI的体验,大多数情况下我们需要考虑到用户手指移动的加速度、反馈、期望等,比如快速的滑动和低速的滑动给用户的心理预期是完全不同的,这方面做得比较完美的要数MacBook上的TouchPad了,从单指移动鼠标、双指窗口内移动,到三指窗口间切换、四指返回Home,给用户的体验算是十分优秀的了。当然这都是交互的内容了,不再过多讨论,一般产品中也不建议做太复杂的手势。
一般情况下我们用的比较多的手势就是单指拖拽、双指缩放图片这样的简单手势,下面的代码是ImageView实现单指和双指这两种手势的代码,没有用到GestureDetector,而是仅仅对onTouch事件进行处理:
注:ImageView 中要添加 android:scaleType="matrix"
float last_x = - 1 ;
float last_y = - 1 ;
mImage . setOnTouchListener ( new OnTouchListener () {
float baseValue ;
@Override
public boolean onTouch (View v , MotionEvent event ) {
// TODO Auto-generated method stub
// return ArtFilterActivity.this.mGestureDetector.onTouchEvent(event);
if (event . getAction () == MotionEvent . ACTION_DOWN ) {
baseValue = 0 ;
float x = last_x = event . getRawX ();
float y = last_y = event . getRawY ();
}
else if (event . getAction () == MotionEvent . ACTION_MOVE ) {
if (event . getPointerCount () == 2 ) {
float x = event . getX ( 0 ) - event . getX ( 1 );
float y = event . getY ( 0 ) - event . getY ( 1 );
float value = ( float ) Math . sqrt (x * x + y * y ); // 计算两点的距离
if (baseValue == 0 ) {
baseValue = value ;
}
else {
if (value - baseValue >= 10 || value - baseValue <= - 10 ) {
float scale = value / baseValue ; // 当前两点间的距离除以手指落下时两点间的距离就是需要缩放的比例。
img_scale (scale ); //缩放图片
}
}
}
else if (event . getPointerCount () == 1 ) {
float x = event . getRawX ();
float y = event . getRawY ();
x -= last_x ;
y -= last_y ;
if (x >= 10 || y >= 10 || x <= - 10 || y <= - 10 )
img_transport (x , y ); //移动图片位置
last_x = event . getRawX ();
last_y = event . getRawY ();
}
}
else if (event . getAction () == MotionEvent . ACTION_UP ) {
}
return true ;
}
});