【发布时间】:2011-06-15 20:14:38
【问题描述】:
我需要创建一个小文本区域。当我双击该文本区域时,它将移动到下一个活动。我该怎么做?
【问题讨论】:
-
长按或按钮是实现此目的的更常见方式。在这里提出了类似的问题:stackoverflow.com/questions/2217670/…
标签: android
我需要创建一个小文本区域。当我双击该文本区域时,它将移动到下一个活动。我该怎么做?
【问题讨论】:
标签: android
如果设置正确,GestureListener 中的OnDoubleTapListener 非常有用。您无需处理每次点击并计算其间的时间。相反,让 Android 为您处理轻按、双击、滚动或投掷可能是什么。使用实现 GestureListener 和 OnDoubleTapListener 的帮助器类 SimpleGestureListener,您不需要做太多事情。
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;
}
});
注意:我测试了很长一段时间以找出return true 和return false 的正确组合是什么。这是这里真正棘手的部分。
另一个注意事项:当您进行测试时,请在真实设备上,而不是模拟器。我真的很难让鼠标足够快地创建一个 onFling 事件。真实设备上的真实手指似乎要快得多。
【讨论】:
更好的选择是创建一个轻量级的抽象类
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);
}
并像使用它
view.setOnClickListener(new DoubleClickListener() {
@Override
public void onSingleClick(View v) {
}
@Override
public void onDoubleClick(View v) {
}
});
【讨论】:
ViewConfiguration.getDoubleTapTimeout() 。
非常简单的逻辑使用下面的代码
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;
}
【讨论】:
long time= System.currentTimeMillis(); 和 System.currentTimeMillis() 而不是 Helper.getCurrentTimeInMilliSeconds()
我采用了一种不同的方法在 android 视图上实现双击。我创建了自己的逻辑来检测双击,它很容易实现。
以下是执行此操作的步骤:
1.在要接收触摸事件的视图上设置onTouchListener。
2.实现onTouch(view,event)方法。 (双击的关键是检测两个 ACTION_DOWN 和 ACTION_UP 事件。为此,我们必须计算两个连续向下事件之间的持续时间)。
实现这一点的逻辑如下:
/* 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;
}
==== 编辑 ======
对我来说,以上内容对于 cooment 中建议的更改是不可接受的 - 超时不适用于上述逻辑。
改用这个
@覆盖 public boolean onTouch(View paramView, MotionEvent 事件) { 开关(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;
}
【讨论】:
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();
}
}
【讨论】:
我遇到了类似的问题,并且解决方案一直有效,直到我想做其他触摸事件,例如滑动和 onLongPress。这些方法从未被调用,所以我必须实现一个 OnDoubleTapListener。我做了如下:
public class MainActivity extends Activity implements OnDoubleTapListener
那么就实现三个方法
@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 方法。 我不知道何时调用其他两种方法,但这对我有用
【讨论】:
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);
}
【讨论】: