移动开发中比较常见的手势操作有放大、缩小、旋转等。但是这其中大多数为两指实现的对图片操作手势。但是个别特殊情况例如对某个对话框进行手势操作,这样就需要用到单指实现操作手势了。相对于两指算法,单指要麻烦一些,特别对于数学不好的童鞋来说很难想到。因此特别写出来让大家参考一下。(虽然旋转的算法也是受了别人的启示才写出来,具体在哪里看到了忘记了)
不BB直接上代码:
public boolean onTouch(View v, MotionEvent event) {
int DEFAULT_MOVE = 10;// 手指移动小于该值认为没有移动
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
parentX = event.getX();
parentY = event.getY();
mLastPoint.set(parentX, parentY);
oldDistance4PointF = distance4PointF(mCenterPoint, mLastPoint);
//在没有点击到view的情况下点击到了父布局
if (!isTouch) {
PublicViewHolder.getInstance().setTextFalse();
}
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
if (!isTouch)
break;
mTouchPoint.set(x, y);
if (translateMode) {
/**
* 判断位移
*/
int changeX = (int) (x - mLastPoint.x);
int changeY = (int) (y - mLastPoint.y);
translationX += changeX;
translationY += changeY;
setTranslationX(translationX);
setTranslationY(translationY);
} else {
/**
* 判断放大缩小
*/
scale();
/**
* 判断旋转
*/
rotation();
}
oldDistance4PointF = distance4PointF(mCenterPoint, mTouchPoint);
mLastPoint.set(x, y);
break;
case MotionEvent.ACTION_UP:
/**
* 判断当位移值小于制定大小 触发编辑事件
*/
if (Math.abs(event.getX() - parentX) < DEFAULT_MOVE && Math.abs(event.getY() - parentY) < DEFAULT_MOVE && isTouch && !isDeleteTouch) {
editListener.onEdit();
}
translateMode = true;
isTouch = false;
break;
}
return true;
}
/**
* 两个点之间的距离
*
* @return
*/
private float distance4PointF(PointF pf1, PointF pf2) {
float disX = Math.abs(pf2.x - pf1.x);
float disY = Math.abs(pf2.y - pf1.y);
return (float) Math.sqrt(disX * disX + disY * disY);
}
private void scale() {
float newDistance4PointF = distance4PointF(mCenterPoint, mTouchPoint);
float vDistance = newDistance4PointF - oldDistance4PointF;
if (vDistance > 0) {
//放大
scaleL(vDistance / oldDistance4PointF);
} else if (vDistance < 0) {
//缩小
scaleM(-vDistance / oldDistance4PointF);
}
}
public float scale = 1;
private float reScale = 1;
private void scaleL(float multiple) {
scale += multiple;
reScale -= multiple;
setScaleX(scale);
setScaleY(scale);
scaleBar(reScale);
}
private void scaleM(float multiple) {
scale -= multiple;
reScale += multiple;
if (scale <= 0.3) {
scale = 0.3f;
return;
}
setScaleX(scale);
setScaleY(scale);
scaleBar(reScale);
}
private void scaleBar(float scale) {
if (scale <= 0.5)
scale = 0.5f;
if (scale >= 1.0)
scale = 1.0f;
touchBar.setScaleX(scale);
touchBar.setScaleY(scale);
deleteBar.setScaleX(scale);
deleteBar.setScaleY(scale);
editBar.setScaleX(scale);
editBar.setScaleY(scale);
}
public float degrees = 0;
//center -> proMove的向量, 我们使用PointF来实现
PointF centerToProMove = new PointF();
//center -> curMove 的向量
PointF centerToCurMove = new PointF();
private void rotation() {
//旋转所组成三角形三边边长
float a = oldDistance4PointF;
float b = distance4PointF(mLastPoint, mTouchPoint);
float c = distance4PointF(mCenterPoint, mTouchPoint);
float cosArc = (a * a + c * c - b * b) / (2 * a * c);
float newDegree = (float) Math.toDegrees(Math.acos(cosArc));
centerToProMove.set((mLastPoint.x - mCenterPoint.x), (mLastPoint.y - mCenterPoint.y));
centerToCurMove.set((mTouchPoint.x - mCenterPoint.x), (mTouchPoint.y - mCenterPoint.y));
//向量叉乘结果, 如果结果为负数, 表示为逆时针, 结果为正数表示顺时针
float result = centerToProMove.x * centerToCurMove.y - centerToProMove.y * centerToCurMove.x;
if (result < 0) {
newDegree = -newDegree;
}
if (Float.valueOf(newDegree).isNaN())
return;
degrees += newDegree;
setRotation(degrees);
}
放大、缩小比较简单大概提一下,由于写这个的时候是判断点击到了一个touchBar之后才能进行手势操作,所以为了避免touchbar缩小太多无法被点到,对放大缩小的设置了一个极值。