DoubleTap in android
我需要创建一个小文本区域。当我双击该文本区域时,它将移动到下一个活动。我怎么能这样做?
如果您正确设置,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } }); |
注意:我测试了很长一段时间才发现
另一个注意事项:测试时,请在真实设备上进行测试,而不是模拟器。我很难让鼠标足够快以创建一个onFling事件。真实设备上的真实手指似乎要快得多。
更好的选择是创建一个轻量级的抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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); } |
并使用它
1 2 3 4 5 6 7 8 9 10 11 12 | view.setOnClickListener(new DoubleClickListener() { @Override public void onSingleClick(View v) { } @Override public void onDoubleClick(View v) { } }); |
在代码下面使用非常简单的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } |
----------
我采用了一种不同的方法来实现对Android视图的双击。我创建了自己的逻辑来检测双击,它很容易实现。
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).
以下是实现此目的的逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /* 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; } |
====编辑======
对我来说,上面的描述是不可接受的,因为上面的逻辑不会超时。
改用它
@覆盖
public boolean onTouch(查看paramView,MotionEvent事件){
switch(event.getAction()&amp; MotionEvent.ACTION_MASK)
{
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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; |
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } |
我有类似的问题和解决方案,直到我想做其他触摸事件,如刷卡和onLongPress。从未调用过这些方法,所以我必须实现一个OnDoubleTapListener。我做了如下:
1 | public class MainActivity extends Activity implements OnDoubleTapListener |
然后只需实现三种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @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; } |
只需实现onDoubleTapEvent方法即可。
我不知道何时调用其他两个方法,但这对我有用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 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(); } } |