I'm facing an issue on how to control Seekbar progress when user ONLY touching the Thumb
I knew it is a duplicated question but here are the links that gave me an idea about it this and this.
After several rounds of testing, below are my working logic result
mySeekbar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Rect rcThumb = mySeekbar.getThumb().getBounds();
int iWidth = rcThumb.width();
if (event.getX() >= (rcThumb.left - iWidth) && event.getX() <= (rcThumb.right + iWidth)) {
return false;
} else
return true;
}
});
Expected result
no drag or tap
during drag or tap
Problem
You can just copy and paste the above code for testing. As we know that when touching or dragging the thumb will be larger, but there is an issue were thumb will be large when not touching it. This issue will not happen often but seldom. Anyway to solve this ? Much help is appreciated.
Problem result
no drag or tap
during drag or tap
After few rounds of testing, I was able to accomplish the result. Cheers :)
private boolean mIsDragging;
private boolean isWithinThumb(MotionEvent event, SeekBar seekBar) {
Rect rcThumb = seekBar.getThumb().getBounds();
Rect rcDetectTouchArea = new Rect();
int iWidth = rcThumb.width();
int iHeight = rcThumb.height();
rcDetectTouchArea.left = rcThumb.left - iWidth;
rcDetectTouchArea.right = rcThumb.right + iWidth;
rcDetectTouchArea.bottom = rcThumb.bottom + iHeight;
Log.i("TAG", "rcDetectSize.left = " + rcDetectTouchArea.left + " | rcDetectSize.right = " + rcDetectTouchArea.right + " | rcDetectSize.bottom = " + rcDetectTouchArea.bottom + " | event.getX()= " + event.getX() + " | event.getY()= " + event.getY() + " | rcThumb area = " + rcDetectTouchArea.contains((int) event.getX(), (int) event.getY()));
return rcDetectTouchArea.contains((int) event.getX(), (int) event.getY());
}
mSbTest.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isWithinThumb(event, mSbTest)) {
mIsDragging = true;
return false;
}
case MotionEvent.ACTION_UP:
if (mIsDragging) {
mIsDragging = false;
return false;
}
if (isWithinThumb(event, mSbTest)) {
return false;
} else {
return true;
}
case MotionEvent.ACTION_MOVE:
if (!mIsDragging) {
return true;
}
}
return onTouchEvent(event);
}
});
Related
So I have a view under my view, that I need to pass to the pinch to zoom. BUT, if the user double taps, than I do not want to pass the double tap to my second view. Because I need the functionality that is set on a double tap to be ignored.
The only problem is that that functionality is set to be called on 2 ACTION_DOWN events received from the touch listener.
Now I tried to make a logic to prevent from doubletapping to work, but make the pinch to zoom work, but it still isn't perfect. IF I tap with 2 fingers, 1 in 1 place of the screen, and then the other in another place, a bit further it will get it as a double tap, and not consume the Touch, as I need.
This is the code for my touchEventListener:
viewTop.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("","double touch event action: ===========================");
Log.i("","double touch event test action:" + event.getPointerId(0));
if(event.getPointerId(0) == 0) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (secondPressed) {
Log.i("", "double touch test : FIRST FINGER: CONSUMED TRUE");
timeLastTouch = System.currentTimeMillis();
return true;
}else {
Log.i("", "double touch DOWN : " + timeLastTouch + "... time passed: " + (System.currentTimeMillis() - timeLastTouch) + "..... location diff: " + (event.getX() - xLastTouch));
Log.i("", "double touch test XLAST : " + xLastTouch + "/" + yLastTouch + " ... XLAST 2 : " + xLastTouch2 + "/" + yLastTouch2);
if (System.currentTimeMillis() - timeLastTouch < 1000 && Math.abs(event.getX() - xLastTouch) < 150 && Math.abs(event.getY() - yLastTouch) < 150) {
Log.i("", "double touch test TRUE DOWN");
secondPressed = true;
timeLastTouch = System.currentTimeMillis();
xLastTouch = event.getX();
yLastTouch = event.getY();
return true;
} else if (System.currentTimeMillis() - timeLastTouch < 1000 && Math.abs(event.getX() - xLastTouch2) < 150 && Math.abs(event.getY() - yLastTouch2) < 150) {
Log.i("", "double touch test TRUE DOWN");
secondPressed = true;
timeLastTouch = System.currentTimeMillis();
return true;
} else {
timeLastTouch = System.currentTimeMillis();
if(xLastTouch2 == -1) {
xLastTouch2 = event.getX();
yLastTouch2 = event.getY();
}else {
xLastTouch = event.getX();
yLastTouch = event.getY();
}
Log.i("", "double touch test FALSE DOWN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! X : " + event.getX() + "/" + event.getY() + ".... TIME: " + (System.currentTimeMillis() - timeLastTouch));
Log.i("", "double touch test FALSE DOWN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DIFF LAST TOUCH: " + Math.abs(event.getX() - xLastTouch) + "/" + Math.abs(event.getY() - yLastTouch));
Log.i("", "double touch test FALSE DOWN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DIFF LAST TOUCH2: " + Math.abs(event.getX() - xLastTouch2) + "/" + Math.abs(event.getY() - yLastTouch2));
return false;
}
}
} else if (event.getAction() == MotionEvent.ACTION_UP) {
handlerTouch.removeCallbacksAndMessages(null);
Log.i("", "double touch test FALSE UP");
timeLastTouch = System.currentTimeMillis();
handlerTouch.postDelayed(new Runnable() {
#Override
public void run() {
resetTouches();
Log.i("", "double touch test : SECOND PRESSED BECOMES FALSE");
}
}, 300);
return true;
} else {
timeLastTouch = System.currentTimeMillis();
xLastTouch = event.getX();
yLastTouch = event.getY();
Log.i("", "double touch ELSE FALSE");
return false;
}
}else if(event.getPointerId(0) == 1){
timeLastTouch = System.currentTimeMillis();
if(event.getAction() == MotionEvent.ACTION_DOWN) {
xLastTouch2 = event.getX();
yLastTouch2 = event.getY();
secondPressed = true;
return false;
}else if(event.getAction() == MotionEvent.ACTION_UP){
Log.i("","double touch test : SECONDARY FINGER: SECOND PRESSED BECOMES FALSE");
handlerTouch.postDelayed(new Runnable() {
#Override
public void run() {
resetTouches();
Log.i("", "double touch test : SECOND PRESSED BECOMES FALSE");
}
}, 300);
}else {
Log.i("","double touch test : SECONDARY FINGER: SECOND PRESSED BECOMES TRUE");
secondPressed = true;
}
return false;
}else {
timeLastTouch = System.currentTimeMillis();
secondPressed = true;
return false;
}
}
});
Where resetTouches is:
private void resetTouches() {
xLastTouch = -1f;
yLastTouch = -1f;
xLastTouch2 = -1f;
yLastTouch2 = -1f;
secondPressed = false;
}
Now I'm kinda blocked here, and don't know what or how to change in order to prevent the double tap to work. Is there by any change any implementation of this that might be easier? What could I change to improve on this?
This did it for me:
final ScaleGestureDetector mScaleDetector = new ScaleGestureDetector(InCallActivity.this, new ScaleGestureDetector.OnScaleGestureListener() {
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
Log.i("", "double touch test2 onScaleEnd: " + detector.getScaleFactor());
app.TouchEvent(0, 1, (int) xFinger1, (int) yFinger1);
if (xFinger2 != 0) {
app.TouchEvent(1, 1, (int) xFinger2, (int) yFinger2);
} else scale(1, (int) (yFinger1));
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
Log.i("", "double touch test2 onScaleBegin: " + detector.getScaleFactor());
app.TouchEvent(0, 0, (int) xFinger1, (int) yFinger1);
if (xFinger2 != 0) {
app.TouchEvent(1, 0, (int) xFinger2, (int) yFinger2);
} else app.TouchEvent(1, 0, (int) xFinger1, (int) yFinger1);
return true;
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
Log.i("", "double touch test2 zoom ongoing, scale: " + detector.getScaleFactor());
app.TouchEvent(0, 2, (int) xFinger1, (int) yFinger1);
if (xFinger2 != 0) {
app.TouchEvent(1, 2, (int) xFinger2, (int) yFinger2);
} else {
scaleValue = detector.getScaleFactor();
scale(2, (int) (yFinger1));
}
return false;
}
});
viewTop.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("", "double touch test2 ON TOUCH: " + event.getPointerId(0) + "x/y: " + event.getX() + "/" + event.getY());
xFinger1 = event.getX(0);
yFinger1 = event.getY(0);
try {
xFinger2 = event.getX(1);
yFinger2 = event.getY(1);
mScaleDetector.onTouchEvent(event);
} catch (Exception e) {
return logicFor1Finger(event, e);
}
return true;
}
});
I am developing an android application, in my application I dynamically create some ImageViews and set that ImageViews in to a RelativeLayout. So I want to drag each image in the layout independently.Now its working but not properly, when I drag image then the image start vibrating and moving slowly. And I wanted to implement Pinch Zoom in this image.Is it possible? And how how can I remove the vibration on moving the image ? If any one know it please help me..
Thanks
This is my onTouchListener()
canvasImage[i].setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
x1 = motionEvent.getX();
y1 = motionEvent.getY();
//Log.v("vvvvvv", "" + x1 + " " + y1);
final int action = motionEvent.getAction();
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
String w = imglayout.getTop() + " " + imglayout.getHeight();
Log.v("wwww", "" + w);
x2 = motionEvent.getX();
y2 = motionEvent.getY();
dx = x2 - canvasImage[finalI].getX();
dy = y2 - canvasImage[finalI].getY();
//Log.v("cccccc", "" + x2 + " " + y2);
moving = true;
break;
case MotionEvent.ACTION_UP:
moving = false;
break;
case MotionEvent.ACTION_MOVE:
if (moving) {
canvasImage[finalI].setX(motionEvent.getX() - dx);
canvasImage[finalI].setY(motionEvent.getY() - dy);
//Log.v("qqqqqq", "" + canvasImage[finalI].getX());
}
break;
}
//mainLayout.invalidate();
return true;
}
});
This is my setCanvasImage() method used to set images into RelativeLayout
public void setCanvasImage() {
int screenSize = getResources().getConfiguration().screenLayout &
Configuration.SCREENLAYOUT_SIZE_MASK;
final int imgCount = dbobj.getFromTemp();
canvasImage = new ImageView[imgCount];
imglayout = (RelativeLayout) findViewById(R.id.canvas);
final String[] strImage = dbobj.getdImage();
imglayout.removeAllViews();
for (int i = 0; i < imgCount; i++) {
canvasImage[i] = new ImageView(this);
canvasImage[i].setTag("img_" + i);
boolean tabletSize = getResources().getBoolean(R.bool.isTablet);
if (tabletSize) {
int imgWidth = 130;
int imgHeight = 130;
RelativeLayout.LayoutParams paramss = new RelativeLayout.LayoutParams(imgWidth, imgHeight);
paramss.setMargins(posLeft, posTop, 0, 0);
canvasImage[i].setLayoutParams(paramss);
canvasImage[i].setScaleType(ScaleType.FIT_XY);
canvasImage[i].setTag(strImage[i]);
setImage(strImage[i], canvasImage[i]);
imglayout.addView(canvasImage[i]);
}
if( screenSize == Configuration.SCREENLAYOUT_SIZE_NORMAL){
int imgWidth = 100;
int imgHeight = 100;
RelativeLayout.LayoutParams paramss = new RelativeLayout.LayoutParams(imgWidth, imgHeight);
paramss.setMargins(posLeft, posTop, 0, 0);
canvasImage[i].setLayoutParams(paramss);
canvasImage[i].setTag(strImage[i]);
setImage(strImage[i], canvasImage[i]);
imglayout.addView(canvasImage[i]);
}
posLeft = posLeft + 15;
}
}
RelativeLayout xml file
<RelativeLayout
android:layout_below="#+id/btnhorscrolvw"
android:layout_width="match_parent"
android:layout_height="500dp"
android:id="#+id/canvas"
android:background="#ffff"
android:orientation="horizontal"
>
</RelativeLayout>
I think this will work.
float dX, dY;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
view.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
break;
default:
return false;
}
return true;
}
You need to use scalx and scaley factor of imageview for implementing pinch zooming
imageview.setScaleX(scalefactor);
imageview.setScaleY(scalefacto);
Android you can adjust the margin left and margin top to for draging the imageview
I am trying to do swipe from both side in Listview but now i only able to do from right side, but i want to do swipe from both left and right please can any one tell me how to do that.
private void swipe(int dis) {
if (dis > mMenuView.getWidth()) {
dis = mMenuView.getWidth();
}
if (dis < 0) {
dis = 0;
}
mContentView.layout(-dis, mContentView.getTop(), mContentView.getWidth() - dis, getMeasuredHeight());
mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(),
mContentView.getWidth() + mMenuView.getWidth() - dis,
mMenuView.getBottom());
}
/onSwipe Function/
public boolean onSwipe(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = (int) event.getX();
isFling = false;
break;
case MotionEvent.ACTION_MOVE:
// Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX());
int dis = (int) (mDownX - event.getX());
if (state == STATE_OPEN) {
dis += mMenuView.getWidth();
}
swipe(dis);
break;
case MotionEvent.ACTION_UP:
if (isFling
|| (mDownX - event.getX()) > (mMenuView.getWidth() / 1.5)) {
// open
smoothOpenMenu();
} else {
// close
smoothCloseMenu();
return false;
}
break;
}
return true;
}
Please go through the above code and suggest me some solution.
So I'm attempting to make a "magnetic poetry" type application. Users will move various Button widgets on the screen. I am using a Button widget since it is the closest to the look of the magnet, though I am open to other options!
The objects are not properly moving with my finger. They're close but they're not exactly in line with my finger. The X coordinate on my phone seems to be fine, but the Y corrdinate is off. Is this perhaps due to the title bar?
private final static int DRAGGING_OFF = 0;
private final static int DRAGGING_ON = 1;
private int dragStatus;
private GestureDetector mGestureDetector;
private int mOffsetX;
private int mOffsetY;
private LayoutParams mOldParams;
private RelativeLayout.LayoutParams lp;
#Override
public boolean onTouchEvent(MotionEvent event) {
if(!mGestureDetector.onTouchEvent(event)) {
if(event.getAction() == MotionEvent.ACTION_MOVE) {
if(dragStatus == DRAGGING_ON) {
Log.e(VIEW_LOG_TAG, "Dragging! RAW -- " + event.getRawX() + " : " + event.getRawY() + " NOT RAW -- " + event.getX() + " : " + event.getY());
int rawX, rawY;
int finalX, finalY;
rawX = (int) event.getRawX();
rawY = (int) event.getRawY();
finalX = rawX - mOffsetX;
finalY = rawY - mOffsetY;
lp.setMargins(finalX, finalY, 0, 0);
this.setLayoutParams(lp);
}
return true;
} else if(event.getAction() == MotionEvent.ACTION_UP) {
if(dragStatus == DRAGGING_ON) {
dragStatus = DRAGGING_OFF;
Log.e(VIEW_LOG_TAG, "Stopped dragging!");
}
return true;
} else {
return super.onTouchEvent(event);
}
} else {
return true;
}
}
private final GestureDetector.SimpleOnGestureListener mListener = new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDown(MotionEvent e) {
int[] location = new int[2];
Log.e(VIEW_LOG_TAG, "Down! RAW -- " + e.getRawX() + " : " + e.getRawY() + " NOT RAW -- " + e.getX() + " : " + e.getY());
dragStatus = DRAGGING_ON;
// Sets the current location of the View in the int[] passed to it; x then y.
getLocationInWindow(location);
Log.e(VIEW_LOG_TAG, "Down location: " + location[0] + " " + location[1]);
mOffsetX = (int) e.getRawX() - location[0];
mOffsetY = (int) e.getRawY() - location[1];
mOldParams = getLayoutParams();
return true;
}
};
I think the issue is that you're not getting the DELTA of the current touch point Y and the cached, last touch point y. You need something like this:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView textView = (TextView) findViewById(R.id.text);
final ImageView image = (ImageView) findViewById(R.id.image);
matrix.setTranslate(1f, 1f);
image.setImageMatrix(matrix);
image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
matrix.getValues(m); //copy matrix values into array
PointF currentXYTouchPoint = new PointF(event.getX(), event.getY());
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN: //start of pressed gesture
lastXYTouchPoint.set(event.getX(), event.getY()); //save the last touchpoint
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
//calculate the change in finger position
float deltaX = currentXYTouchPoint.x - lastXYTouchPoint.x;
float deltaY = currentXYTouchPoint.y - lastXYTouchPoint.y;
matrix.postTranslate(deltaX, deltaY); //move the entire image by the deltas
image.setImageMatrix(matrix);
// save this last starting touchpoint
lastXYTouchPoint.set(currentXYTouchPoint.x, currentXYTouchPoint.y);
break;
}
textView.setText("TouchPoint started at " + currentXYTouchPoint.x + ", " + currentXYTouchPoint.y + " & the matrix is now " + Arrays.toString(m));
return true;
}
});
}
Adapt it to your own purposes, but the basic idea is there.
I have a custom View with bitmaps on it that the user can drag about.
I want to make it so when they long click one of them I can pop up a context menu with options such as reset position etc.
In the custom View I add my OnLongClickListener:
this.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// show context menu..
return true;
}
});
And override onTouchEvent to look something like this:
public boolean onTouchEvent(MotionEvent event) {
handleDrag(event);
super.onTouchEvent(event);
return true;
}
The handleDrag function finds what object is been pressed, and handles updating it's position.
My problem is that when I start to drag an image the OnLongClickListener fires also. I'm not sure the best way around this.
I've tried adding a threshold to handleDrag to return false if user touches down but doesn't attempt to drag, but I'm finding it still difficult to get the correct handler fired.
Can anyone suggest a way to skip the OnLongClickListener while dragging?
I think I have this solved through tweaking my threshold approach.
First, I changed my onTouchEvent to look like this:
public boolean onTouchEvent(MotionEvent event) {
mMultiTouchController.handleDrag(event);
return super.onTouchEvent(event);
}
They now both fire, so I then changed my OnLongClickListener to the following:
this.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (!mMultiTouchController.has_moved) {
// Pop menu and done...
return false;
}
return true;
}
});
(mMultiTouchController is the class containing all my gesture detection code).
The key here is within this class, I added the bool 'has_moved'. When I go to start a drag I then compute the delta:
float diffX = Math.abs(mCurrPtX - mPrevPt.getX());
float diffY = Math.abs(mCurrPtY - mPrevPt.getY());
if (diffX < threshold && diffY < threshold) {
has_moved = false;
return;
}
Now when the onLongClick fires I know whether to take action or not.
The final piece was to set:
setHapticFeedbackEnabled(false);
in my View so that the user doesn't get a vibrate every time the longClick fires but no action is taken. I plan to do the vibration manually as a next step.
This seems to be ok so far, hope that helps anyone who has come across a similar situation as this one.
I would stop using the onLongClickListener and just implement your own, which is pretty easy to do. Then you have the control you need to keep them from interfering with each other.
The following code implements the following gestures: drag, tap, double tap, long click, and pinch.
static final short NONE = 0;
static final short DRAG = 1;
static final short ZOOM = 2;
static final short TAP = 3;
static final short DOUBLE_TAP = 4;
static final short POST_GESTURE = 5;
short mode = NONE;
static final float MIN_PINCH_DISTANCE = 30f;
static final float MIN_DRAG_DISTANCE = 5f;
static final float DOUBLE_TAP_MAX_DISTANCE = 30f;
static final long MAX_DOUBLE_TAP_MS = 1000;
static final long LONG_PRESS_THRESHOLD_MS = 2000;
public class Vector2d {
public float x;
public float y;
public Vector2d() {
x = 0f;
y = 0f;
}
public void set(float newX, float newY) {
x = newX;
y = newY;
}
public Vector2d avgVector(Vector2d remote) {
Vector2d mid = new Vector2d();
mid.set((remote.x + x)/2, (remote.y + y)/2);
return mid;
}
public float length() {
return (float) Math.sqrt(x * x + y * y);
}
public float distance(Vector2d remote) {
float deltaX = remote.x - x;
float deltaY = remote.y - y;
return (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
}
}
private Vector2d finger1 = new Vector2d();
private Vector2d finger2 = new Vector2d();
private Vector2d pinchStartDistance = new Vector2d();
private Vector2d pinchMidPoint;
private Vector2d fingerStartPoint = new Vector2d();
private long gestureStartTime;
private Marker selectedMarker;
#Override
public boolean onTouch(View v, MotionEvent event) {
// Dump touch event to log
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
finger1.set(event.getX(), event.getY());
if (mode == TAP) {
if (finger1.distance(fingerStartPoint) < DOUBLE_TAP_MAX_DISTANCE) {
mode = DOUBLE_TAP;
} else {
mode = NONE;
gestureStartTime = SystemClock.uptimeMillis();
}
} else {
gestureStartTime = SystemClock.uptimeMillis();
}
fingerStartPoint.set(event.getX(), event.getY());
break;
case MotionEvent.ACTION_POINTER_DOWN:
finger2.set(event.getX(1), event.getY(1));
pinchStartDistance.set(Math.abs(finger1.x - finger2.x), Math.abs(finger1.y - finger2.y));
Log.d(TAG, String.format("pinch start distance = %f, %f", pinchStartDistance.x, pinchStartDistance.y));
if (pinchStartDistance.length() > MIN_PINCH_DISTANCE) {
if (pinchStartDistance.x < MIN_PINCH_DISTANCE) {
pinchStartDistance.x = MIN_PINCH_DISTANCE;
}
if (pinchStartDistance.y < MIN_PINCH_DISTANCE) {
pinchStartDistance.y = MIN_PINCH_DISTANCE;
}
pinchMidPoint = finger1.avgVector(finger2);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM" );
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mode == ZOOM) {
Vector2d pinchEndDistance = new Vector2d();
pinchEndDistance.set(Math.abs(finger1.x - finger2.x), Math.abs(finger1.y - finger2.y));
if (pinchEndDistance.x < MIN_PINCH_DISTANCE) {
pinchEndDistance.x = MIN_PINCH_DISTANCE;
}
if (pinchEndDistance.y < MIN_PINCH_DISTANCE) {
pinchEndDistance.y = MIN_PINCH_DISTANCE;
}
Log.d(TAG, String.format("pinch end distance = %f, %f", pinchEndDistance.x, pinchEndDistance.y));
zoom(pinchMidPoint, pinchStartDistance.x/pinchEndDistance.x, pinchStartDistance.y/pinchEndDistance.y);
// Set mode to "POST_GESTURE" so that when the other finger lifts the handler won't think it was a
// tap or something.
mode = POST_GESTURE;
} else if (mode == NONE) {
// The finger wasn't moved enough for it to be considered a "drag", so it is either a tap
// or a "long press", depending on how long it was down.
if ((SystemClock.uptimeMillis() - gestureStartTime) < LONG_PRESS_THRESHOLD_MS) {
Log.d(TAG, "mode=TAP");
mode = TAP;
selectedMarker = checkForMarker(finger1);
if (selectedMarker != null) {
Log.d(TAG, "Selected marker, mode=NONE");
mode = NONE;
((Activity) parent).showDialog(ResultsActivity.DIALOG_MARKER_ID);
}
}
else {
Log.d(TAG, "mode=LONG_PRESS");
addMarker(finger1);
requestRender();
}
} else if (mode == DOUBLE_TAP && (SystemClock.uptimeMillis() - gestureStartTime) < MAX_DOUBLE_TAP_MS) {
// The finger was again not moved enough for it to be considered a "drag", so it is
// a double-tap. Change the center point and zoom in.
Log.d(TAG, "mode=DOUBLE_TAP");
zoom(fingerStartPoint, 0.5f, 0.5f);
mode = NONE;
} else {
mode = NONE;
Log.d(TAG, "mode=NONE" );
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == NONE || mode == TAP || mode == DOUBLE_TAP) {
finger1.set(event.getX(), event.getY());
if (finger1.distance(fingerStartPoint) > MIN_DRAG_DISTANCE) {
Log.d(TAG, "mode=DRAG" );
mode = DRAG;
scroll(fingerStartPoint.x - finger1.x, fingerStartPoint.y - finger1.y);
}
}
else if (mode == DRAG) {
scroll(finger1.x - event.getX(), finger1.y - event.getY());
finger1.set(event.getX(), event.getY());
}
else if (mode == ZOOM) {
for (int i=0; i<event.getPointerCount(); i++) {
if (event.getPointerId(i) == 0) {
finger1.set(event.getX(i), event.getY(i));
}
else if (event.getPointerId(i) == 1) {
finger2.set(event.getX(i), event.getY(i));
}
else {
Log.w(TAG, String.format("Unknown motion event pointer id: %d", event.getPointerId(i)));
}
}
}
break;
}
return true;
}
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_" ).append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid " ).append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")" );
}
sb.append("[" );
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#" ).append(i);
sb.append("(pid " ).append(event.getPointerId(i));
sb.append(")=" ).append((int) event.getX(i));
sb.append("," ).append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";" );
}
sb.append("]" );
Log.d(TAG, sb.toString());
}
//This code is to handle the gestures detection
final Handler handler = new Handler();
private Runnable mLongPressRunnable;
detector = new GestureDetector(this, new MyGestureDectector());
view.setOnTouchListener(new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#SuppressWarnings("deprecation")
#Override
public boolean onTouch(View v, MotionEvent event) {
detector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
handler.postDelayed(mLongPressRunnable, 1000);
}
if ((event.getAction() == MotionEvent.ACTION_MOVE)
|| (event.getAction() == MotionEvent.ACTION_UP)) {
handler.removeCallbacks(mLongPressRunnable);
}
}
return true;
}
});
mLongPressRunnable = new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "long", Toast.LENGTH_SHORT)
.show();
}
};
class MyGestureDectector implements GestureDetector.OnDoubleTapListener,
OnGestureListener {
//Implement all the methods
}