【问题标题】:DoubleTap in android [duplicate]android中的DoubleTap [重复]
【发布时间】:2011-06-15 20:14:38
【问题描述】:

我需要创建一个小文本区域。当我双击该文本区域时,它将移动到下一个活动。我该怎么做?

【问题讨论】:

标签: android


【解决方案1】:

如果设置正确,GestureListener 中的OnDoubleTapListener 非常有用。您无需处理每次点击并计算其间的时间。相反,让 Android 为您处理轻按、双击、滚动或投掷可能是什么。使用实现 GestureListenerOnDoubleTapListener 的帮助器类 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 truereturn false 的正确组合是什么。这是这里真正棘手的部分。

另一个注意事项:当您进行测试时,请在真实设备上,而不是模拟器。我真的很难让鼠标足够快地创建一个 onFling 事件。真实设备上的真实手指似乎要快得多。

【讨论】:

  • 这非常适合我的情况。我需要防止用户多次触发动画。非常感谢。
  • 对我来说很棒!我必须做的一件事是删除 GestureDetector 的“Test.this”参数。它已贬值但有效。我不断收到错误消息:“错误:(35、79)错误:不是封闭类:测试”。知道是什么原因造成的吗?
  • 我找到了一个能够传递上下文的修复程序。将此添加到 onCreate(): final Context context = getApplicationContext();然后传递“上下文”而不是“Test.this”。
  • 这很好用。但它会破坏文本视图中的滚动。
  • 出色使用匿名课程的奖励积分。
【解决方案2】:

更好的选择是创建一个轻量级的抽象类

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) {

        }
    });

【讨论】:

  • 当用户尝试双击时它不会同时调用 onsingleclick 和 ondoubleclick 吗?
  • 系统双击超时为ViewConfiguration.getDoubleTapTimeout()
  • 您将始终获得单点点击。需要有一个300ms的定时器
【解决方案3】:

非常简单的逻辑使用下面的代码

    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()
【解决方案4】:

---------

我采用了一种不同的方法在 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;    

}

【讨论】:

  • 为了完成上述工作,需要进行一些小改动。 1)更改:静态最终MAX_DURATION = 500;到静态最终 int MAX_DURATION = 500; 2) 改变: if(totalTime
  • birdman 您的更改有所帮助,但超时不起作用,请检查我的编辑以获取更正的超时逻辑。
【解决方案5】:
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();
 }
}

【讨论】:

    【解决方案6】:

    我遇到了类似的问题,并且解决方案一直有效,直到我想做其他触摸事件,例如滑动和 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 方法。 我不知道何时调用其他两种方法,但这对我有用

    【讨论】:

    • 如何设置监听?
    【解决方案7】:
    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); 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      • 2018-10-08
      相关资源
      最近更新 更多