在某个point我是非常需要像百度地图那些自定义手势动作,能够放大,缩小,移动,旋转,但是在网上却找不到一个立马下载能使用的包,不说那么多,我先上接口代码:
import android.view.MotionEvent;
/**
* Created by mr.Hao on 20**/**/**.
*/
public interface OnGestuerListner {
public boolean onOneTouch(MotionEvent event);//点击一个点
public void onTranslate(float x, float y);//手指移动,有正负值,直接累加即可
public void onLarge(float px, float centerX, float centerY);//放大手势 ,相差多少,中心点坐标
public void onDecrease(float px, float centerX, float centerY);//缩小手势,相差多少,中心点坐标
public void onRotate(float degree, float centerX, float centerY);//旋转手势,中心点
public void onDoubleClick();//双击
}
看到接口怎么样?感觉流口水了吧?,那么我们继续上实现的代码:
import android.util.Log;
import android.view.MotionEvent;
/**
* Created by mr.Hao on 20**/**/**.
*/
public class GestuerControl {
private OnGestuerListner listener;
public GestuerControl(OnGestuerListner listener) {
this.listener = listener;
}
//移动
float mX;//移动的x轴
float mY;//移动的y轴
//是否在放大手势
private boolean isScale = false;
//放大的距离
float distance = 0;
public boolean OnEvent(MotionEvent event) {
if (this.listener == null) {
return false;
}
//现获得触摸点数量
int pointerCount = event.getPointerCount();
if (pointerCount == 1) {
//判断是否在放大手势,因为放大手势最后会remove
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isScale = false;
mX = event.getX();
mY = event.getY();
return this.listener.onOneTouch(event);
case MotionEvent.ACTION_MOVE:
if (!isScale) {
//移动了多少个像素
float difX = Math.abs(mX - event.getX());
float difY = Math.abs(mY - event.getY());
if (mX < event.getX() && mY == event.getY()) {
//向右
listener.onTranslate(difX, 0);
} else if (mX > event.getX() && mY == event.getY()) {
//向左
listener.onTranslate(-difX, 0);
} else if (mY < event.getY() && mX == event.getX()) {
//向下
listener.onTranslate(0, difY);
} else if (mY > event.getY() && mX == event.getX()) {
//向上
listener.onTranslate(0, -difY);
//共同移动
} else if (mX < event.getX() && mY < event.getY()) {
//向右,向下
listener.onTranslate(difX, difY);
} else if (mX < event.getX() && mY > event.getY()) {
//向右,向上
listener.onTranslate(difX, -difY);
} else if (mX > event.getX() && mY < event.getY()) {
//向左,向下
listener.onTranslate(-difX, difY);
} else if (mX > event.getX() && mY > event.getY()) {
//向左,向下
listener.onTranslate(-difX, -difY);
}
mX = event.getX();
mY = event.getY();
return this.listener.onOneTouch(event);
}
break;
case MotionEvent.ACTION_UP:
distance = 0;
lastX1 = -1;
lastY1 = -1;
lastX2 = -1;
lastY2 = -1;
//开始判断是否是双击
long clickTime = System.currentTimeMillis();
//判断范围
float clickX = event.getX();
float clickY = event.getY();
//先判断点击范围
if (Math.abs(clickX - lastClickX) < ENABLE_CLICK_DIS && Math.abs(clickY - lastClickY) < ENABLE_CLICK_DIS) {
//判断点击时间
if ((clickTime - lastClickTime) < DOUBLE_CLICK_TIME) {
listener.onDoubleClick();
//双击后复原,防止多重点击
lastClickTime = 0;
lastClickX = 0f;
lastClickY = 0f;
} else {
//如果是第一次点击就赋值
lastClickTime = clickTime;
}
} else {
lastClickX = clickX;
lastClickY = clickY;
lastClickTime = clickTime;
}
break;
}
} else if (pointerCount > 1) {
onTwoTouch(event);
}
return true;
}
//最后点击的位置
private float lastClickX = 0f;
private float lastClickY = 0f;
//在这个点击返回内判断是点击有效
private final static float ENABLE_CLICK_DIS = 50;
//最后点击的时间
private long lastClickTime = 0;
//当两次点击小于这个时间被认为是双击
private final static long DOUBLE_CLICK_TIME = 500;
private float lastX1 = -1;
private float lastY1 = -1;
private float lastX2 = -1;
private float lastY2 = -1;
private void onTwoTouch(MotionEvent event) {
float x1 = event.getX(0);
float y1 = event.getY(0);
float x2 = event.getX(1);
float y2 = event.getY(1);
if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
isScale = true;
distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
//缩放手势
if (distance == 0) {
distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
} else {
float tempD = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
float d = tempD - distance;
if (Math.abs(d) > 50) {
//第一次是否是错误的点,可能是上次的
distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
} else {
isScale = true;
if (d > 0) {
this.listener.onLarge(d, getCenter(x1, x2), getCenter(y1, y2));
} else if (d < 0) {
this.listener.onDecrease(Math.abs(d), getCenter(x1, x2), getCenter(y1, y2));
}
distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
}
}
} else if (event.getAction() == MotionEvent.ACTION_POINTER_UP) {
distance = 0;
}
//旋转手势,触碰获得坐标点
if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
lastX1 = x1;
lastY1 = y1;
lastX2 = x2;
lastY2 = y2;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (lastX1 == -1 ||
lastY1 == -1 ||
lastX2 == -1 ||
lastY2 == -1) {
lastX1 = x1;
lastY1 = y1;
lastX2 = x2;
lastY2 = y2;
} else {
//计算两条直线的方程
//y=kx+b
//第一条直线
double k1;
double b1;
//先求出斜率
k1 = (lastY1 - lastY2) / (lastX1 - lastX2);
//求出b
b1 = (lastY2 * lastX1 - lastY1 * lastX2) / (lastX1 - lastX2);
//第二条直线
//先求出斜率
double k2 = (y1 - y2) / (x1 - x2);
//求出b
double b2 = (y2 * x1 - y1 * x2) / (x1 - x2);
//斜率不相等才有交点
if (k1 != k2) {
//计算交点坐标
double centerX = (b2 - b1) / (k1 - k2);
double centerY = (b2 * k1 - b1 * k2) / (k1 - k2);
//计算交点是否在两条直线上
double lastMaxX = lastX1 > lastX2 ? lastX1 : lastX2;
double lastMinX = lastX1 < lastX2 ? lastX1 : lastX2;
double lastMaxY = lastY1 > lastY2 ? lastY1 : lastY2;
double lastMinY = lastY1 < lastY2 ? lastY1 : lastY2;
double maxX = x1 > x2 ? x1 : x2;
double minX = x1 < x2 ? x1 : x2;
double maxY = y1 > y2 ? y1 : y2;
double minY = y1 < y2 ? y1 : y2;
if (centerX < lastMaxX &&
centerX > lastMinX &&
centerY < lastMaxY &&
centerY > lastMinY &&
centerX < maxX &&
centerX > minX &&
centerY < maxY &&
centerY > minY) {
//移动计算角度
//分别计算第一次的触碰的半径的平方,即两点距离公式的平方,两个手指一动分别形成两个三个型A,B
//A半径^2
double A_R1 = (Math.pow(lastX1 - centerX, 2) + Math.pow(lastY1 - centerY, 2));
//B半径^2
double B_R1 = (Math.pow(lastX2 - centerX, 2) + Math.pow(lastY2 - centerY, 2));
//然后计算一动后产生的第二次的半径
//A半径^2
double A_R2 = (Math.pow(x1 - centerX, 2) + Math.pow(y1 - centerY, 2));
//B半径^2
double B_R2 = (Math.pow(x2 - centerX, 2) + Math.pow(y2 - centerY, 2));
//然后计算两端的第三段长度,形成一个三角形
//A形成的第三条边
double A_A3 = (Math.pow(lastX1 - x1, 2) + Math.pow(lastY1 - y1, 2));
//B形成的第三条边
double B_A3 = (Math.pow(lastX2 - x2, 2) + Math.pow(lastY2 - y2, 2));
//然后用余弦定理分别把角求出
// <c=(a^2+b^2-c^2)/(2ab),a,b,c分别为三角形的三条边长
//A三角形的角度余弦值
double A_AngleCos = (A_R1 + A_R2 - A_A3) / (2 * Math.sqrt(A_R1) * Math.sqrt(A_R2));
//是否超出定义范围,余弦值定义为[-1,1]
A_AngleCos = A_AngleCos > 1 ? 1 : A_AngleCos;
A_AngleCos = A_AngleCos < -1 ? -1 : A_AngleCos;
//B三角形的角度余弦值
double B_AngleCos = (B_R1 + B_R2 - B_A3) / (2 * Math.sqrt(B_R1) * Math.sqrt(B_R2));
//是否超出定义范围,余弦值定义为[-1,1]
B_AngleCos = B_AngleCos > 1 ? 1 : B_AngleCos;
B_AngleCos = B_AngleCos < -1 ? -1 : B_AngleCos;
//判断向量方向
boolean isClockwiseA = ((lastX1 - centerX) * (y1 - centerY) - (lastY1 - centerY) * (x1 - centerX)) > 0;
boolean isClockwiseB = ((lastX2 - centerX) * (y2 - centerY) - (lastY2 - centerY) * (x2 - centerX)) > 0;
//A角大小,Math.acos弧度转换成角度
double A_Angle = Math.toDegrees(Math.acos(A_AngleCos));
//B角大小
double B_Angle = Math.toDegrees(Math.acos(B_AngleCos));
//计算得出的余弦值转换角度
double angle = A_Angle > B_Angle ? A_Angle : B_Angle;
boolean isClockwise = A_Angle > B_Angle ? isClockwiseA : isClockwiseB;
if (angle > 10 || angle < -10 || angle == Double.NaN || angle == Double.NEGATIVE_INFINITY || angle == Double.POSITIVE_INFINITY) {
Log.e("NAN", "lastX1=" + lastX1 + ",lastY1=" + lastY1 + ",x1=" + x1 + ",y1=" + y1 + ",centerX=" + centerX + ",centerY=" + centerY + ",angle=" + angle);
lastX1 = x1;
lastY1 = y1;
lastX2 = x2;
lastY2 = y2;
} else {
this.listener.onRotate((float) (isClockwise ? -angle : angle), (float) centerX, (float) centerY);
}
} else {
lastX1 = -1;
lastY1 = -1;
lastX2 = -1;
lastY2 = -1;
}
}
lastX1 = x1;
lastY1 = y1;
lastX2 = x2;
lastY2 = y2;
}
} else if (event.getAction() == MotionEvent.ACTION_POINTER_UP) {
lastX1 = -1;
lastY1 = -1;
lastX2 = -1;
lastY2 = -1;
}
}
//计算两点的中心点
private float getCenter(float v1, float v2) {
return (v1 + v2) / 2;
}
}
这就是这几个手势的全部代码,使用更简单方便,上上上上代码:
import android.view.MotionEvent;
import android.view.View;
/**
* Created by mr.Hao on 20**/**/**.
*/
public class MyView extends View implements OnGestuerListner {
//获得手势实例
private GestuerControl gestuerControl = new GestuerControl(this);
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean flag = gestuerControl.OnEvent(event);
if (!flag) {
return super.onTouchEvent(event);
}
return true;
}
@Override
public boolean onOneTouch(MotionEvent event) {
return true;
}
@Override
public void onTranslate(float x, float y) {
}
@Override
public void onLarge(float px, float centerX, float centerY) {
}
@Override
public void onDecrease(float px, float centerX, float centerY) {
}
@Override
public void onRotate(float degree, float centerX, float centerY) {
}
@Override
public void onDoubleClick() {
}
}
到这里的话,操作已经全部完成了,手势动作就是:
单个手指移动:触发onTranslate 移动
两个手指同时向一个方向旋转:触发onRotate 旋转
两个手指同一直线上反方向移动:触发 onDecrease 缩小 和 onLarge 放大
单个手指双击屏幕:触发 onDoubleClick 双击
okok!!结束了!!!很简单!!!需要的赶紧cv大法。
转载请注明!