package com.asha.vrlib;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import com.asha.vrlib.model.MDPinchConfig;
import java.util.LinkedList;
import java.util.List;
/**
* Created by hzqiujiadi on 16/5/6.
* hzqiujiadi ashqalcn@gmail.com
*
* reference
* https://github.com/boycy815/PinchImageView/blob/master/pinchimageview/src/main/java/com/boycy815/pinchimageview/PinchImageView.java
*/
public class MDTouchHelper {
private MDVRLibrary.IAdvanceGestureListener mAdvanceGestureListener;
private List<MDVRLibrary.IGestureListener> mClickListeners = new LinkedList<>();
private GestureDetector mGestureDetector;
private int mCurrentMode = 0;
private PinchInfo mPinchInfo = new PinchInfo();
private boolean mPinchEnabled;
private float minScale;
private float maxScale;
private float mSensitivity;
private float defaultScale;
private float mGlobalScale;
private static final int MODE_INIT = 0;
private static final int MODE_PINCH = 1;
public MDTouchHelper(Context context) {
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mCurrentMode == MODE_PINCH) return false;
for (MDVRLibrary.IGestureListener listener : mClickListeners){
listener.onClick(e);
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (mCurrentMode == MODE_PINCH) return false;
if (mAdvanceGestureListener != null)
mAdvanceGestureListener.onDrag(distanceX / mGlobalScale, distanceY / mGlobalScale);
return true;
}
});
}
public boolean handleTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mCurrentMode == MODE_PINCH) {
// end anim
}
mCurrentMode = MODE_INIT;
} else if (action == MotionEvent.ACTION_POINTER_UP) {
// one point up
if (mCurrentMode == MODE_PINCH) {
// more than 2 pointer
if (event.getPointerCount() > 2) {
if (event.getAction() >> 8 == 0) {
// 0 up
markPinchInfo(event.getX(1), event.getY(1), event.getX(2), event.getY(2));
} else if (event.getAction() >> 8 == 1) {
// 1 up
markPinchInfo(event.getX(0), event.getY(0), event.getX(2), event.getY(2));
}
}
}
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
// >= 2 pointer
mCurrentMode = MODE_PINCH;
markPinchInfo(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
} else if (action == MotionEvent.ACTION_MOVE) {
// >= 2 pointer
if (mCurrentMode == MODE_PINCH && event.getPointerCount() > 1) {
float distance = calDistance(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
// float[] lineCenter = MathUtils.getCenterPoint(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
// mLastMovePoint.set(lineCenter[0], lineCenter[1]);
handlePinch(distance);
}
}
mGestureDetector.onTouchEvent(event);
return true;
}
public void scaleTo(float scale){
setScaleInner(mPinchInfo.setScale(scale));
}
public void reset(){
setScaleInner(mPinchInfo.reset());
}
private void handlePinch(float distance) {
if (mPinchEnabled){
setScaleInner(mPinchInfo.pinch(distance));
}
}
private void setScaleInner(float scale){
if (mAdvanceGestureListener != null)
mAdvanceGestureListener.onPinch(scale);
mGlobalScale = scale;
}
private void markPinchInfo(float x1, float y1, float x2, float y2) {
mPinchInfo.mark(x1, y1, x2, y2);
}
private static float calDistance(float x1, float y1, float x2, float y2) {
return (float) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
public void addClickListener(MDVRLibrary.IGestureListener gestureListener) {
if (gestureListener != null) mClickListeners.add(gestureListener);
}
public void setAdvanceGestureListener(MDVRLibrary.IAdvanceGestureListener listener) {
this.mAdvanceGestureListener = listener;
}
public void setPinchEnabled(boolean mPinchEnabled) {
this.mPinchEnabled = mPinchEnabled;
}
public void setPinchConfig(MDPinchConfig pinchConfig) {
this.minScale = pinchConfig.getMin();
this.maxScale = pinchConfig.getMax();
this.mSensitivity = pinchConfig.getSensitivity();
this.defaultScale = pinchConfig.getDefaultValue();
this.defaultScale = Math.max(minScale, this.defaultScale);
this.defaultScale = Math.min(maxScale, this.defaultScale);
setScaleInner(this.defaultScale);
}
private class PinchInfo{
private float x1;
private float y1;
private float x2;
private float y2;
private float oDistance;
private float prevScale;
private float currentScale;
public void mark(float x1, float y1, float x2, float y2){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
oDistance = calDistance(x1, y1, x2, y2);
prevScale = currentScale;
}
public float pinch(float distance) {
if (oDistance == 0) oDistance = distance;
float scale = distance / oDistance - 1;
scale *= mSensitivity;
currentScale = prevScale + scale;
// range
currentScale = Math.max(currentScale, minScale);
currentScale = Math.min(currentScale, maxScale);
return currentScale;
}
public float setScale(float scale){
prevScale = scale;
currentScale = scale;
return currentScale;
}
public float reset(){
return setScale(defaultScale);
}
}
}