作者:某人_Valar
如需转载请保留原文链接
android随手势旋转的控件
相关文章
本文结构
- 1.简介
- 2.使用步骤
- 3.源码
1 简介
前面两篇文章分别介绍了对图片和控件的缩放、移动,这次就是对控件的旋转了。
2 使用步骤
旋转控件的原理其实是和上一篇 android控件的缩放,移动一样的。
不过旋转的重点在于角度的计算,只要我们将手指旋转的角度计算处理,再调用android view自带的setRotation()方法就行了。
图中绿色小框就是一个要旋转的view,中间的红点为view的中心点,当我们从触摸点1滑到触摸点2时,两条线中的夹角就是我们需要的。
/**
*根据坐标系中的3点确定夹角的方法(注意:夹角是有正负的)
*/
public float angle(Point cen, Point first, Point second)
{
float dx1, dx2, dy1, dy2;
dx1 = first.x - cen.x;
dy1 = first.y - cen.y;
dx2 = second.x - cen.x;
dy2 = second.y - cen.y;
// 计算三边的平方
float ab2 = (second.x - first.x) * (second.x - first.x) + (second.y - first.y) * (second.y - first.y);
float oa2 = dx1*dx1 + dy1*dy1;
float ob2 = dx2 * dx2 + dy2 *dy2;
// 根据两向量的叉乘来判断顺逆时针
boolean isClockwise = ((first.x - cen.x) * (second.y - cen.y) - (first.y - cen.y) * (second.x - cen.x)) > 0;
// 根据余弦定理计算旋转角的余弦值
double cosDegree = (oa2 + ob2 - ab2) / (2 * Math.sqrt(oa2) * Math.sqrt(ob2));
// 异常处理,因为算出来会有误差绝对值可能会超过一,所以需要处理一下
if (cosDegree > 1) {
cosDegree = 1;
} else if (cosDegree < -1) {
cosDegree = -1;
}
// 计算弧度
double radian = Math.acos(cosDegree);
// 计算旋转过的角度,顺时针为正,逆时针为负
return (float) (isClockwise ? Math.toDegrees(radian) : -Math.toDegrees(radian));
}
当我们计算出夹角之后,只需要在手势监听中给view设置setRotation()既可以了。
3 DragScaleView 的完整代码
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class DragScaleView extends android.support.v7.widget.AppCompatImageView implements View.OnTouchListener {
protected int lastX;
protected int lastY;
//初始的旋转角度
private float oriRotation = 0;
private static String TAG = "sxlwof";
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction()& MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
oriLeft = v.getLeft();
oriRight = v.getRight();
oriTop = v.getTop();
oriBottom = v.getBottom();
lastY = (int) event.getRawY();
lastX = (int) event.getRawX();
oriRotation = v.getRotation();
Log.d(TAG, "ACTION_DOWN: "+oriRotation);
}
delDrag(v, event, action);
invalidate();
return false;
}
/**
* 处理拖动事件
*
* @param v
* @param event
* @param action
*/
protected void delDrag(View v, MotionEvent event, int action) {
switch (action) {
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
Point center = new Point(oriLeft+(oriRight-oriLeft)/2,oriTop+(oriBottom-oriTop)/2);
Point first = new Point(lastX,lastY);
Point second = new Point((int) event.getRawX(),(int) event.getRawY());
oriRotation += angle(center,first,second);
v.setRotation(oriRotation);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
break;
}
}
public float angle(Point cen, Point first, Point second)
{
float dx1, dx2, dy1, dy2;
dx1 = first.x - cen.x;
dy1 = first.y - cen.y;
dx2 = second.x - cen.x;
dy2 = second.y - cen.y;
// 计算三边的平方
float ab2 = (second.x - first.x) * (second.x - first.x) + (second.y - first.y) * (second.y - first.y);
float oa2 = dx1*dx1 + dy1*dy1;
float ob2 = dx2 * dx2 + dy2 *dy2;
// 根据两向量的叉乘来判断顺逆时针
boolean isClockwise = ((first.x - cen.x) * (second.y - cen.y) - (first.y - cen.y) * (second.x - cen.x)) > 0;
// 根据余弦定理计算旋转角的余弦值
double cosDegree = (oa2 + ob2 - ab2) / (2 * Math.sqrt(oa2) * Math.sqrt(ob2));
// 异常处理,因为算出来会有误差绝对值可能会超过一,所以需要处理一下
if (cosDegree > 1) {
cosDegree = 1;
} else if (cosDegree < -1) {
cosDegree = -1;
}
// 计算弧度
double radian = Math.acos(cosDegree);
// 计算旋转过的角度,顺时针为正,逆时针为负
return (float) (isClockwise ? Math.toDegrees(radian) : -Math.toDegrees(radian));
}
}