手势控制控件的缩放,平移和旋转:
mapView是要移动的控件,TouchLayout是手势控制的区域,具体代码如下:
touchLayout.setOnTouchListener(new TouchListener());
class TouchListener implements View.OnTouchListener {
//以下代码为地图的手势控制
private final int DRAG = 1;
private final int ZOOM = 2;
private final int NONE = 0;
private int mode = NONE;
private float x_down = 0;
private float y_down = 0;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldScale = 1;
private float oldDist = 1f;
private float oldAngle = 0;
private float oldRotation = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
x_down = event.getX();
y_down = event.getY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
oldDist = spacing(event);
oldAngle = angle(event);
midPoint(mid, event);
break;
case MotionEvent.ACTION_MOVE:
if (mode == ZOOM) {
//缩放
float newDist = spacing(event);
float newScale = (newDist) / oldDist * oldScale;
Log.i("map缩放", "onTouchEvent: " + newScale + " ");
mapView.setScaleX(newScale);
mapView.setScaleY(newScale);
oldDist = newDist;
oldScale = newScale;
//旋转
float newAngle = angle(event);
float newRotation = newAngle - oldAngle + oldRotation;
Log.i("map旋转", "onTouch: " + newRotation + " " + oldRotation);
mapView.setRotation(newRotation);
oldRotation = newRotation;
oldAngle = newAngle;
} else if (mode == DRAG) {
float d_x = event.getX() - x_down;
float d_y = event.getY() - y_down;
Log.i("map平移", "onTouchEvent: " + d_x + " " + d_y);
mapView.offsetLeftAndRight((int) (0.5 + d_x));
mapView.offsetTopAndBottom((int) (0.5 + d_y));
x_down = event.getX();
y_down = event.getY();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
return true;
}
// 触碰两点间距离
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
// 取手势中心点
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
// 取旋转角度
private float angle(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
我也试过在mapview中重写onTouchEvent方法,主要代码和以上代码基本几乎完全相同,就不再贴出来了。但是,却发现一个问题,如果基本原封不动的照抄以上代码,在mapview中重写onTouchEvent方法的效果没有在在父控件调用setOnTouchListener方法的效果好。简单来说,完全相同的代码,在setOnTouchListener方法中要更流畅,无论是缩放,还是平移,都明显比onTouchEvent方法的效果要快。。如果要是两者达到相同的体验效果,需对onTouchEvent方法做少许修改。。。不知道是什么原因~
参考文章:
https://blog.youkuaiyun.com/eieihihi/article/details/45668189
https://blog.youkuaiyun.com/happy_bug/article/details/7895244
另外,附上一下onTouchEvent和setOnTouchListener的关系:
1、如果setOnTouchListener中的onTouch方法返回值是true则onTouchEvent方法将不会被执行;
2、只有当setOnTouchListener中的onTouch方法返回值是false时onTouchEvent方法才被执行。