I need to create a small text area.Within that text area when i double click,it will move to next activity.How could i do this?
7 Answers
If you do the setup right, the OnDoubleTapListener, within the GestureListeneris very useful. You dont need to handle each single tap and count time in between. Instead let Android handle for you what a tap, a double-tap, a scroll or fling might be. With the helper class SimpleGestureListener that implements the GestureListener and OnDoubleTapListener you dont need much to do.
findViewById(R.id.touchableText).setOnTouchListener(new OnTouchListener() { private GestureDetector gestureDetector = new GestureDetector(Test.this, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { Log.d("TEST", "onDoubleTap"); return super.onDoubleTap(e); } ... // implement here other callback methods like onFling, onScroll as necessary }); @Override public boolean onTouch(View v, MotionEvent event) { Log.d("TEST", "Raw event: " + event.getAction() + ", (" + event.getRawX() + ", " + event.getRawY() + ")"); gestureDetector.onTouchEvent(event); return true; } }); Note: I tested around quite a while to find out, what the right mixture of return true and return false is. This was the really tricky part here.
Another note: When you test this, do it on a real device, instead of the emulator. I had real trouble getting the mouse fast enough to create an onFling event. Real fingers on real devices seem to be much faster.
5 Comments
A better alternative is to create a lightweight Abstract Class
public abstract class DoubleClickListener implements OnClickListener { private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds long lastClickTime = 0; @Override public void onClick(View v) { long clickTime = System.currentTimeMillis(); if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){ onDoubleClick(v); lastClickTime = 0; } else { onSingleClick(v); } lastClickTime = clickTime; } public abstract void onSingleClick(View v); public abstract void onDoubleClick(View v); } And use it like
view.setOnClickListener(new DoubleClickListener() { @Override public void onSingleClick(View v) { } @Override public void onDoubleClick(View v) { } }); very simple logic use below code
boolean firstTouch = false; @Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction() == event.ACTION_DOWN){ if(firstTouch && (Helper.getCurrentTimeInMilliSeconds() - time) <= 300) { //do stuff here for double tap Log.e("** DOUBLE TAP**"," second tap "); firstTouch = false; } else { firstTouch = true; time = Helper.getCurrentTimeInMilliSeconds(); Log.e("** SINGLE TAP**"," First Tap time "+time); return false; } } return true; } 1 Comment
long time= System.currentTimeMillis(); and System.currentTimeMillis() instead of Helper.getCurrentTimeInMilliSeconds()----------
I took a different approach for implementing double-tap on android views. I created my own logic for detecting double tap and it's very easy to implement.
Here are the steps for doing this:
1. Set onTouchListener on the view you want to receive the touch event.
2. Implement the onTouch(view,event) method. (In double tap the key is to detect two ACTION_DOWN and ACTION_UP events. For this we will have to calculate the time duration between two successive down-up events).
Here is the logic for achieving this:
/* variable for counting two successive up-down events */ int clickCount = 0; /*variable for storing the time of first click*/ long startTime; /* variable for calculating the total time*/ long duration; /* constant for defining the time duration between the click that can be considered as double-tap */ static final MAX_DURATION = 500; @Override public boolean onTouch (View v, MotionEvent event) { switch(event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: startTime = System.currentTimeMillis(); clickCount++; break; case MotionEvent.ACTION_UP: long time = System.currentTimeMillis() - startTime; duration= duration + time; if(clickCount == 2) { if(totalTime <= DURATION) { Toast.makeText(captureActivity.this, "double tap",Toast.LENGTH_LONG).show(); } clickCount = 0; duration = 0; break; } } return true; } ==== EDIT ======
For me the above is not acceptable with the changes suggested in the cooment - the time out does not work for the above logic.
use this instead
@Override public boolean onTouch(View paramView, MotionEvent event) { switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP: clickCount++; if (clickCount==1){ startTime = System.currentTimeMillis(); } else if(clickCount == 2) { long duration = System.currentTimeMillis() - startTime; if(duration <= ONE_SECOND) { Toast.makeText(captureActivity.this, "double tap",Toast.LENGTH_LONG).show(); clickCount = 0; duration = 0; }else{ clickCount = 1; startTime = System.currentTimeMillis(); } break; } } return true; }
2 Comments
X_View.setOnClickListener(new View.OnClickListener() { @Override public void onItemClick(View view) { long timeNow=Calendar.getInstance().getTimeInMillis(); long timeLastTapped=Long.valueOf(view.getTag().toString()); // Initially set to zero in adapter final int minDurationBetweenDoubleTap=500; if(timeLastTapped != 0) if( timeNow- timeLastTapped < minDurationBetweenDoubleTap) { Toast.makeText(getApplicationContext(), "DoubleTapped", 10).show(); } view.setTag(""+timeNow); } Comments
import android.app.Activity; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.GestureDetector.SimpleOnGestureListener; import android.widget.Toast; public class SimpleGestureFilter extends SimpleOnGestureListener { public final static int SWIPE_UP = 1; public final static int SWIPE_DOWN = 2; public final static int SWIPE_LEFT = 3; public final static int SWIPE_RIGHT = 4; public final static int MODE_TRANSPARENT = 0; public final static int MODE_SOLID = 1; public final static int MODE_DYNAMIC = 2; private final static int ACTION_FAKE = -13; private int swipe_Min_Distance = 100; private int swipe_Max_Distance = 350; private int swipe_Min_Velocity = 100; private int mode = MODE_DYNAMIC; private boolean running = true; private boolean tapIndicator = false; private Activity context; private GestureDetector detector; private SimpleGestureListener listener; public SimpleGestureFilter(Activity context,SimpleGestureListener sgf) { this.context = context; this.detector = new GestureDetector(context, this); this.listener = sgf; } public void onTouchEvent(MotionEvent me) { // TODO Auto-generated method stub if(!this.running) return; boolean result=this.detector.onTouchEvent(me); if(this.mode==MODE_SOLID) me.setAction(MotionEvent.ACTION_CANCEL); else if(this.mode==MODE_DYNAMIC) { if(me.getAction()==ACTION_FAKE) me.setAction(MotionEvent.ACTION_UP); else if(result) me.setAction(MotionEvent.ACTION_CANCEL); else if(this.tapIndicator) { me.setAction(MotionEvent.ACTION_DOWN); this.tapIndicator=false; } } } public void setMode(int m) { this.mode=m; } public int getMode() { return this.mode; } public void setEnabled(boolean status) { this.running=status; } public void setSwipeMaxDistance(int distance) { this.swipe_Max_Distance=distance; } public void setSwipeMinDistance(int distance) { this.swipe_Min_Distance=distance; } public int getSwipeMaxDistance() { return this.swipe_Max_Distance; } public int getSwipeMinDistance() { return this.swipe_Min_Distance; } public int getSwipeMinVelocity() { return this.swipe_Min_Velocity; } public boolean onFling(MotionEvent e1,MotionEvent e2,float velocityX,float velocityY) { final float xDistance=Math.abs(e1.getX()-e2.getX()); final float yDistance=Math.abs(e1.getY()-e2.getY()); if(xDistance>this.swipe_Max_Distance || yDistance> this.swipe_Max_Distance) return false; velocityX = Math.abs(velocityX); velocityY = Math.abs(velocityY); boolean result=false; if(velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance) { if(e1.getX() > e2.getX()) // right to left Move this.listener.onSwipe(SWIPE_LEFT); else this.listener.onSwipe(SWIPE_RIGHT); result=true; } else if(velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance) { if(e1.getY() > e2.getY()) // bottom to top Move this.listener.onSwipe(SWIPE_UP); else this.listener.onSwipe(SWIPE_DOWN); result=true; } return result; } public boolean onSingleTapUp(MotionEvent e) { this.tapIndicator=true; return false; } public boolean onDoubleTap(MotionEvent e) { this.listener.onDoubleTap(); return false; } public boolean onDoubleTapEvent(MotionEvent e) { return true; } public boolean onSingleTapConfirmed(MotionEvent e) { if(this.mode==MODE_DYNAMIC) { e.setAction(ACTION_FAKE); this.context.dispatchTouchEvent(e); } return false; } static interface SimpleGestureListener { void onSwipe(int direction); void onDoubleTap(); } } Comments
I had i similar problem and the solutions work until i wanted to do other touch events like swiping and onLongPress. Those methods were never invoked so I had to implement an OnDoubleTapListener. I did as follows:
public class MainActivity extends Activity implements OnDoubleTapListener Then just implement three methods
@Override public boolean onDoubleTapEvent(MotionEvent e) { if(e.getAction()==1) { Toast.makeText(getApplicationContext(), "DOUBLE TAP",Toast.LENGTH_SHORT).show(); // TODO Auto-generated method stub // Implement code here!!! } return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { return true; } Just implement the onDoubleTapEvent method. I don't know when the other two methods are invoked, but this works for me