我正在编写一个组件来处理缩放,旋转和平移的手势识别。可悲的是,缩放不起作用,它没有收到缩小,并且放大效果不好,因为当视图很大时,它什么也没做,似乎只有在到达视图边缘时才起作用。 / p>
public class MyGestureDetector implements ScaleGestureDetector.OnScaleGestureListener {
private static final int INVALID_POINTER_ID = -1;
private float fX, fY, sX, sY;
private int ptrID1, ptrID2;
private float mAngle;
private float mPreviousAngle = 0;
private float mDeltaAngle;
private float dX, dY;
private boolean isClick, isMove;
private float mRatio = 1.0f;
private int mBaseDist;
private float mBaseRatio;
private final static float STEP = 200;
private Vector2D movement = new Vector2D();
private Vector2D movementRaw = new Vector2D();
private ScaleGestureDetector mScaleGestureDetector;
private OnGestureListener mListener;
public float getAngle() {
return mAngle;
}
public float getScaling() {
return mRatio;
}
public Vector2D getMovement() {
return movement;
}
public Vector2D getMovementRaw() {
return movementRaw;
}
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale = false;
public MyGestureDetector(OnGestureListener listener){
gestureScale = new ScaleGestureDetector((Context) listener, this);
mListener = listener;
ptrID1 = INVALID_POINTER_ID;
ptrID2 = INVALID_POINTER_ID;
}
public boolean onTouchEvent(MotionEvent event, View view){
gestureScale.onTouchEvent(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
isClick=true;
isMove=true;
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
currentPosition = new Vector2D(event.getRawX(), event.getRawY());
ptrID1 = event.getPointerId(event.getActionIndex());
break;
case MotionEvent.ACTION_POINTER_DOWN:
if(ptrID2 == INVALID_POINTER_ID ) {
ptrID2 = event.getPointerId(event.getActionIndex());
int pt1 = event.findPointerIndex(ptrID1);
int pt2 = event.findPointerIndex(ptrID2);
if(pt1 < 0 || pt2 < 0 ){
return false;
}
mBaseDist = getDistance(event);
mBaseRatio = mRatio;
startX = event.getRawX() - view.getX() + centerX;
startY = event.getRawY() - view.getY() + centerY;
sX = event.getX(pt1);
sY = event.getY(pt1);
fX = event.getX(pt2);
fY = event.getY(pt2);
isClick=false;
isMove=false;
}
break;
case MotionEvent.ACTION_MOVE:
if(ptrID1 != INVALID_POINTER_ID && ptrID2 != INVALID_POINTER_ID) {
int pt1 = event.findPointerIndex(ptrID1);
int pt2 = event.findPointerIndex(ptrID2);
if(pt1 < 0 || pt2 < 0 ){
return false;
}
/// Scaling
float delta = (getDistance(event) - mBaseDist) / STEP;
float multi = (float) Math.pow(2, delta);
//mRatio = Math.min(10.0f, Math.max(0.5f, mBaseRatio * multi));
/// Rotating
float nfX, nfY, nsX, nsY;
nsX = event.getX(pt1);
nsY = event.getY(pt1);
nfX = event.getX(pt2);
nfY = event.getY(pt2);
if(nsX < 0 || nsY < 0 || nfX < 0 || nfY < 0){
return false;
}
mAngle = angleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);
mDeltaAngle = mAngle - mPreviousAngle;
if (mListener != null) {
mPreviousAngle = mAngle;
mListener.OnRotation(this);
//mListener.OnScaling(this);
}
}else{
if(!currentPosition.toString().equals(new Vector2D(event.getRawX(), event.getRawY()).toString())){
isClick=false;
}
currentPosition = new Vector2D(event.getRawX(), event.getRawY());
movement.set(event.getRawX() + dX, event.getRawY() + dY);
movementRaw.set(event.getRawX() , event.getRawY() );
if (isMove && mListener != null) {
mListener.OnMove(this);
}
}
break;
case MotionEvent.ACTION_UP:
if(isClick) {
if (mListener != null) {
mListener.OnClick(this);
}
}else{
mListener.OnStopGesture(this);
}
ptrID1 = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
ptrID2 = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_CANCEL:
ptrID1 = INVALID_POINTER_ID;
ptrID2 = INVALID_POINTER_ID;
break;
}
return true;
}
int getDistance(MotionEvent event) {
int dx = (int) (event.getX(0) - event.getX(1));
int dy = (int) (event.getY(0) - event.getY(1));
return (int) (Math.sqrt(dx * dx + dy * dy));
}
float centerX, centerY, startR, startScale, startX, startY, startRotation, startA;
TextView tv;
Vector2D currentPosition;
private float angleBetweenLines (float fX, float fY, float sX, float sY, float nfX, float nfY, float nsX, float nsY)
{
float angle1 = (float) Math.atan2( (fY - sY), (fX - sX) );
float angle2 = (float) Math.atan2( (nfY - nsY), (nfX - nsX) );
float angle = ((float)Math.toDegrees(angle1 - angle2)) % 360;
if (angle < -180.f) angle += 360.0f;
if (angle > 180.f) angle -= 360.0f;
return angle;
}
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
scaleFactor *= scaleGestureDetector.getScaleFactor();
//scaleFactor = (scaleFactor < 1 ? : scaleFactor); // prevent our view from becoming too small //
scaleFactor = ((float)((int)(scaleFactor * 100))) / 100; // Change precision to help with jitter when user just rests their fingers //
mRatio = scaleFactor;
if (mListener != null) {
mListener.OnScaling(this);
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
inScale = false;
}
public static interface OnGestureListener {
public void OnRotation(MyGestureDetector rotationDetector);
public void OnScaling(MyGestureDetector rotationDetector);
public void OnMove(MyGestureDetector rotationDetector);
public void OnClick(MyGestureDetector rotationDetector);
public void OnStopGesture(MyGestureDetector rotationDetector);
}
}