如何检测双击?

我对双击有意见。我实现了 onGestureListenergestureDetector,但我不知道问题出在哪里,这是我的代码:

 public class home extends TabActivity implements OnGestureListener {
/** Called when the activity is first created. */


private EditText queryText;
private ResultsAdapter m_adapter;
private ProgressDialog pd;
final Handler h = new Handler();
private TabHost mTabHost;
private ArrayList<SearchItem> sResultsArr = new ArrayList<SearchItem>();
private String queryStr;
private JSONObject searchResponse;
private GestureDetector gestureScanner;


final Runnable mUpdateResults = new Runnable() {
public void run() {
updateListUi();
}
};


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);


Button search = (Button)findViewById(R.id.search);
Button testButt = (Button)findViewById(R.id.testbutt);
queryText = (EditText)findViewById(R.id.query);
ListView lvr = (ListView)findViewById(R.id.search_results);


//initialise the arrayAdapter
this.m_adapter = new ResultsAdapter(home.this, R.layout.listrow, sResultsArr);
lvr.setAdapter(this.m_adapter);
lvr.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);


}


});
gestureScanner = new GestureDetector(this,this);
gestureScanner.setOnDoubleTapListener(new OnDoubleTapListener(){
public boolean onDoubleTap(MotionEvent e) {
//viewA.setText("-" + "onDoubleTap" + "-");
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);


return false;
}
public boolean onDoubleTapEvent(MotionEvent e) {
// viewA.setText("-" + "onDoubleTapEvent" + "-");
return false;
}
public boolean onSingleTapConfirmed(MotionEvent e) {
//viewA.setText("-" + "onSingleTapConfirmed" + "-");
return false;
}


});




//initialise tab contents
mTabHost = getTabHost();
mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Home").setContent(R.id.homepage));
mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Search Results").setContent(R.id.tab2));
mTabHost.setCurrentTab(0);


//sets the respective listeners
testButt.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {


if(mTabHost.getTabWidget().getVisibility()==View.GONE){
mTabHost.getTabWidget().setVisibility(View.VISIBLE);
}
else{
mTabHost.getTabWidget().setVisibility(View.GONE);
}
}
});


search.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
sResultsArr.clear();
queryStr = "http://rose.mosuma.com/mobile?query=" + queryText.getText().toString();
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);
goSearch();
}
});
}


//updates the listUI whenever after receiving the response from the server
public void updateListUi(){
if(sResultsArr.size() > 0){


}


try{
String ptypename;
int count;
LinearLayout ptypebar = (LinearLayout)findViewById(R.id.productCat);
ptypebar.removeAllViews();
JSONArray ptypes = searchResponse.getJSONArray("ptypes");
for(int index =0;index < ptypes.length();index++){
JSONObject ptype = ptypes.getJSONObject(index);
count = ptype.getInt("count");
ptypename = ptype.getString("ptypename");


//add into tab 2's UI


//ImageView icon = new ImageView(this);
TextView t = new TextView(home.this);
t.setText(ptypename + " (" + count + ")");
ptypebar.addView(t);
}
}
catch(JSONException e){


}
//if(m_adapter.getItems() != sResultsArr){
ArrayList<SearchItem> a  = m_adapter.getItems();
a = sResultsArr;
//}
m_adapter.notifyDataSetChanged();
pd.dismiss();
}


public void goSearch(){
mTabHost.setCurrentTab(1);


//separate thread for making http request and updating the arraylist
Thread t = new Thread() {
public void run() {


searchResponse = sendSearchQuery(queryStr);
try{
JSONArray results = searchResponse.getJSONArray("results");


//this is stupid. i probably have to see how to make a json adapter
for(int index =0;index < results.length();index++){


JSONObject product = results.getJSONObject(index);


//gets the searched products from the json object
URL imgUrl =  new URL(product.getString("image"));
String productname = product.getString("productname");
String ptypename = product.getString("ptypename");
int pid = product.getInt("pid");
int positive = product.getInt("pos");
int negative = product.getInt("neg");
int neutral = product.getInt("neu");




SearchItem item  = new SearchItem(imgUrl,productname,ptypename,neutral,positive,negative,pid);
sResultsArr.add(item);
}
}
catch(JSONException e){


}
catch(Exception e){


}
//returns back to UI therad
h.post(mUpdateResults);
}
};
t.start();
}


//sends a request with qry as URL
//and receives back a JSONobject as response
public JSONObject sendSearchQuery(String qry){
HttpRequest r = new HttpRequest();
JSONObject response = r.sendHttpRequest(qry);
return response;
}


@Override
public boolean onDown(MotionEvent arg0) {
return gestureScanner.onTouchEvent(arg0);
}


@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}


@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub


}


@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}


@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub


}


@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}

哦,还有一个问题,如果我的 ListView有一个 onItemClickListener,机器人能在单击和双击之间检测到它吗?

125261 次浏览

你为什么不用长按?还是你已经把它用在别的地方了?长时间按压的优点:

  • 在用户界面指南中,长按是一种推荐的交互方式,而双触则不是。
  • 这正是用户所期望的; 用户可能找不到 Double Touch 操作,因为他们不会去寻找它
  • 已经是 处理了。
  • 实施双点触摸将影响单点触摸的处理,因为你将不得不等待,看看是否每一个单点触摸变成双点触摸之前,你可以处理它。

您可以使用 GestureDetector:

public class MyView extends View {


GestureDetector gestureDetector;


public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// creating new gesture detector
gestureDetector = new GestureDetector(context, new GestureListener());
}


// skipping measure calculation and drawing


// delegate the event to the gesture detector
@Override
public boolean onTouchEvent(MotionEvent e) {
return gestureDetector.onTouchEvent(e);
}




private class GestureListener extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
float x = e.getX();
float y = e.getY();


Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")");


return true;
}
}
}

您可以重写侦听器的其他方法,以获得单个点击、触发等。

这是我的解决方案,它使用默认的 setOnItemClickListener()。我也有同样的任务要完成。很快我将在我的 github 上发布示例和自定义类。 简要说明。我不确定以毫秒为单位的时间是否对系统(请参阅 ViewConfiguration.getDoubleTapTimeout()源代码)来决定单击和双击之间的差异。

编辑: 点击这里查看: Https://github.com/nikoladespotoski/doubletaplistview Https://github.com/nikoladespotoski/doubletaplistviewhandler

如果您不希望去自定义视图,那么您可以使用以下方法。 例如 ImageView

// class level


GestureDetector gestureDetector;
boolean tapped;
ImageView imageView;


// inside onCreate of Activity or Fragment
gestureDetector = new GestureDetector(context,new GestureListener());

//--------------------------------------------------------------------------------

public class GestureListener extends
GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {


return true;
}


// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {


tapped = !tapped;


if (tapped) {






} else {






}


return true;
}
}

//--------------------------------------------------------------------------------

用于 ImageView

imageView.setOnTouchListener(new OnTouchListener() {


@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gestureDetector.onTouchEvent(event);
}


});

作为 GestureDetector 的一个轻量级替代品,您可以使用这个类

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


}
});

GuestureDetecter 在大多数设备上工作良好,我想知道如何在双击事件中定制两次点击之间的时间,我无法做到这一点。我用“ Bughi”“ DoubleClickListner”更新了上面的代码,添加了一个使用处理程序的定时器,它在单击一个特定延迟之后执行代码,如果双击在该延迟之前执行,它取消了定时器和单击任务,只执行双击任务。 Code is working 代码正在运行 Fine 使它成为双击 listner 的完美工具:

  private Timer timer = null;  //at class level;
private int DELAY   = 500;


view.setOnClickListener(new DoubleClickListener() {


@Override
public void onSingleClick(View v) {


final Handler  handler          = new Handler();
final Runnable mRunnable        = new Runnable() {
public void run() {
processSingleClickEvent(v); //Do what ever u want on single click


}
};


TimerTask timertask = new TimerTask() {
@Override
public void run() {
handler.post(mRunnable);
}
};
timer   =   new Timer();
timer.schedule(timertask, DELAY);


}


@Override
public void onDoubleClick(View v) {
if(timer!=null)
{
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge();  //Frees Memory by erasing cancelled Tasks.
}
processDoubleClickEvent(v);//Do what ever u want on Double Click


}
});

我的解决方案,可能会有帮助。

long lastTouchUpTime = 0;
boolean isDoubleClick = false;


private void performDoubleClick() {
long currentTime = System.currentTimeMillis();
if(!isDoubleClick && currentTime - lastTouchUpTime < DOUBLE_CLICK_TIME_INTERVAL) {
isDoubleClick = true;
lastTouchUpTime = currentTime;
Toast.makeText(context, "double click", Toast.LENGTH_SHORT).show();
}
else {
lastTouchUpTime = currentTime;
isDoubleClick = false;
}
}
boolean nonDoubleClick = true, singleClick = false;
private long firstClickTime = 0L;
private final int DOUBLE_CLICK_TIMEOUT = 200;


listview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int pos, long id) {
// TODO Auto-generated method stub
Handler handler = new Handler();
handler.postDelayed(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
if (singleClick) {
Toast.makeText(getApplicationContext(), "Single Tap Detected", Toast.LENGTH_SHORT).show();
}
firstClickTime = 0L;
nonDoubleClick = true;
singleClick = false;
}
}, 200);
if (firstClickTime == 0) {
firstClickTime = SystemClock.elapsedRealtime();
nonDoubleClick = true;
singleClick = true;
} else {
long deltaTime = SystemClock.elapsedRealtime() - firstClickTime;
firstClickTime = 0;
if (deltaTime < DOUBLE_CLICK_TIMEOUT) {
nonDoubleClick = false;
singleClick = false;
Toast.makeText(getApplicationContext(), "Double Tap Detected", Toast.LENGTH_SHORT).show();
}
}


}
});

实现单击和双击

public abstract class DoubleClickListener implements View.OnClickListener {


private static final long DOUBLE_CLICK_TIME_DELTA = 200;


private long lastClickTime = 0;


private View view;


private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
onSingleClick(view);
}
};


private void runTimer(){
handler.removeCallbacks(runnable);
handler.postDelayed(runnable,DOUBLE_CLICK_TIME_DELTA);
}


@Override
public void onClick(View view) {
this.view = view;
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
handler.removeCallbacks(runnable);
lastClickTime = 0;
onDoubleClick(view);
} else {
runTimer();
lastClickTime = clickTime;
}
}


public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);

}

public class MyView extends View {


GestureDetector gestureDetector;


public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// creating new gesture detector
gestureDetector = new GestureDetector(context, new GestureListener());
}


// skipping measure calculation and drawing


// delegate the event to the gesture detector
@Override
public boolean onTouchEvent(MotionEvent e) {
return gestureDetector.onTouchEvent(e);
}




private class GestureListener extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
float x = e.getX();
float y = e.getY();


Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")");


return true;
}
}
}

Bughi & Jayant Arora 的 copypast 解决方案:

public abstract class DoubleClickListener implements View.OnClickListener {
private int position;
private Timer timer;


private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds


long lastClickTime = 0;


public DoubleClickListener (int position) {
this.position = position;
}


@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
if (timer != null) {
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge();  //Frees Memory by erasing cancelled Tasks.
}
onDoubleClick(v, position);
} else {
final Handler handler = new Handler();
final Runnable mRunnable = () -> {
onSingleClick(v, position);
};
TimerTask timertask = new TimerTask() {
@Override
public void run() {
handler.post(mRunnable);
}
};
timer = new Timer();
timer.schedule(timertask, DOUBLE_CLICK_TIME_DELTA);


}
lastClickTime = clickTime;
}


public abstract void onSingleClick(View v, int position);
public abstract void onDoubleClick(View v, int position);}

将“ Bughi”“ DoubleClickListner”和“ Jayant Arora”Timer 组合在一个包含类中:

public abstract class DoubleClickListener implements OnClickListener {


private Timer timer = null;  //at class level;
private int DELAY   = 400;


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){
processDoubleClickEvent(v);
} else {
processSingleClickEvent(v);
}
lastClickTime = clickTime;
}






public void processSingleClickEvent(final View v){


final Handler handler=new Handler();
final Runnable mRunnable=new Runnable(){
public void run(){
onSingleClick(v); //Do what ever u want on single click


}
};


TimerTask timertask=new TimerTask(){
@Override
public void run(){
handler.post(mRunnable);
}
};
timer=new Timer();
timer.schedule(timertask,DELAY);


}


public void processDoubleClickEvent(View v){
if(timer!=null)
{
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge();  //Frees Memory by erasing cancelled Tasks.
}
onDoubleClick(v);//Do what ever u want on Double Click
}


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


}
});

简易的 dhruvi 代码

public abstract class DoubleClickListener implements View.OnClickListener {


private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds


long lastClickTime = 0;
boolean tap = true;


@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
onDoubleClick(v);
tap = false;
} else
tap = true;


v.postDelayed(new Runnable() {
@Override
public void run() {
if(tap)
onSingleClick();
}
},DOUBLE_CLICK_TIME_DELTA);


lastClickTime = clickTime;
}


public abstract void onDoubleClick(View v);


public abstract void onSingleClick();
}

等效的 C # 代码,我用来实现相同的功能,甚至可以自定义接受 N 次点击

public interface IOnTouchInterface
{
void ViewTapped();
}


public class MultipleTouchGestureListener : Java.Lang.Object, View.IOnTouchListener
{
int clickCount = 0;
long startTime;
static long MAX_DURATION = 500;
public int NumberOfTaps { get; set; } = 7;


readonly IOnTouchInterface interfc;


public MultipleTouchGestureListener(IOnTouchInterface tch)
{
this.interfc = tch;
}


public bool OnTouch(View v, MotionEvent e)
{
switch (e.Action)
{
case MotionEventActions.Down:
clickCount++;
if(clickCount == 1)
startTime = Utility.CurrentTimeSince1970;
break;
case MotionEventActions.Up:
var currentTime = Utility.CurrentTimeSince1970;
long time = currentTime - startTime;
if(time <= MAX_DURATION * NumberOfTaps)
{
if (clickCount == NumberOfTaps)
{
this.interfc.ViewTapped();
clickCount = 0;
}
}
else
{
clickCount = 0;
}
break;
}
return true;
}
}


public static class Utility
{
public static long CurrentTimeSince1970
{
get
{
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
DateTime dtNow = DateTime.Now;
TimeSpan result = dtNow.Subtract(dt);
long seconds = (long)result.TotalMilliseconds;
return seconds;
}
}
}

目前,以上代码在引发 ViewTated 事件之前接受7作为点击次数。 但它可以定制任何号码

双击 还有单击

只能双击

通过使用 SimpleOnGestureListener(如 Hannes Niederhausen 的回答所示) ,很容易检测到视图上的双击。

private class GestureListener extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}


@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}

我看不出为此重新发明逻辑(如 Bughi 的回答)有什么大的优势。

双水龙头和单水龙头延迟

你也可以使用 SimpleOnGestureListener来区分单击和双击的互斥。要做到这一点,您只需覆盖 onSingleTapConfirmed。这将延迟单击代码的运行,直到系统确定用户没有双击(即延迟 > ViewConfiguration.getDoubleTapTimeout())。毫无疑问,没有理由为此重新发明所有的逻辑(正如在 这个这个和其他答案中所做的那样)。

private class GestureListener extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}


@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}


@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}

双击和单击无延迟

onSingleTapConfirmed的潜在问题是延迟。有时明显的延迟是不可接受的。在这种情况下,您可以将 onSingleTapConfirmed替换为 onSingleTapUp

private class GestureListener extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}


@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}


@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}

但是,您需要认识到,如果有一个双击,将调用 都有 onSingleTapUp 还有 onDoubleTap。(这基本上就是 Bughi 的回答所做的,也是一些评论者所抱怨的。)您要么需要使用延迟,要么同时调用这两个方法。这是不可能有一个单点击没有延迟,同时知道用户是否要再次点击。

如果单击延迟对你来说是不可接受的,那么你有两个选择:

  • 接受 onSingleTapUponDoubleTap都将被调用进行双击。只要适当地划分你的逻辑,这样就无所谓了。这基本上就是我在自定义键盘上实现大写锁定双击时所做的事情。
  • 不要使用双击。对于大多数事情来说,这不是一个直观的 UI 操作。作为 Dave Webb 建议,长按可能更好。您还可以使用 SimpleOnGestureListener实现这一点:

    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
    
    
    @Override
    public boolean onDown(MotionEvent e) {
    return true;
    }
    
    
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
    return true;
    }
    
    
    @Override
    public void onLongPress(MotionEvent e) {
    
    
    }
    }
    

我使用 Kotlin 协奏曲实现了一个简单的自定义方法(Java 可以通过线程完成)。

var click = 0


view.setOnClickListener{
click++
clicksHandling()
}


fun clicksHandling() {
if (click == 1) {
launch {
delay(300) // custom delay duration between clicks
// if user didn't double tap then click counter still 1
if (click == 1) {
// single click handling
runOnUiThread {
// whatever you wanna do on UI thread
}
}


click = 0 //reset counter , this will run no matter single / double tap
}
//double click handling
if (click == 2) {
// whatever on double click
}
}

线程 + 接口 = DoubleTapListener,AnyTap 侦听器等

在本例中,我使用一个线程实现了 DoubleTap 监听器。 您可以使用任何 View 对象添加我的侦听器,就像使用任何 ClickListener 一样。 使用这种方法,您可以轻松实现任何类型的单击侦听器。

yourButton.setOnClickListener(new DoubleTapListener(this));

1)我的 Listrener 类

public class DoubleTapListener  implements View.OnClickListener{


private boolean isRunning= false;
private int resetInTime =500;
private int counter=0;
private DoubleTapCallback listener;


public DoubleTapListener(Context context){
listener = (DoubleTapCallback)context;
Log.d("Double Tap","New");
}


@Override
public void onClick(View v) {


if(isRunning){
if(counter==1)
listener.onDoubleClick(v);
}


counter++;


if(!isRunning){
isRunning=true;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(resetInTime);
isRunning = false;
counter=0;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}

2)聆听者回应

public interface DoubleTapCallback {


public void onDoubleClick(View v);


}

3)积极参与活动

public class MainActivity extends AppCompatActivity implements DoubleTapCallback{


private Button button;
private int counter;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


button   = (Button)findViewById(R.id.button);
button.setOnClickListener(new DoubleTapListener(this));  // Set mt listener


}


@Override
public void onDoubleClick(View v) {
counter++;
textView.setText(counter+"");
}

相关连结:

您可以看到完整的工作代码 给你

您可以使用 GestureDetectorCompat类实现双击。 在这个例子中,当双击文本视图时,你可以做你的逻辑。

public class MainActivity extends AppCompatActivity {


GestureDetectorCompat gestureDetectorCompat;
TextView textElement;


@Override
protected void onCreate(Bundle savedInstanceState) {
.....
textElement = findViewById(R.id.textElement);
gestureDetectorCompat = new GestureDetectorCompat(this, new MyGesture());
textElement.setOnTouchListener(onTouchListener);


}


View.OnTouchListener onTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetectorCompat.onTouchEvent(event);
return true;
}
};
class MyGesture extends GestureDetector.SimpleOnGestureListener {


@Override
public boolean onDown(MotionEvent e) {
return true;
}


@Override
public boolean onDoubleTap(MotionEvent e) {
// whatever on double click
return true;
}
}

如果你正在使用 Kotlin,那么你可以这样做:

我花了很多时间把这段代码转换成 Kotlin,希望能节省一些人的时间

创建一个手势检测器:

      val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
override fun onDoubleTap(e: MotionEvent): Boolean {


Toast.makeText(this@DemoActivity,"Double Tap",Toast.LENGTH_LONG).show()


//Show or hide Ip address on double tap
toggleIPaddressVisibility()


return true;
}


override fun onLongPress(e: MotionEvent) {
super.onLongPress(e);


//rotate frame on long press
toggleFrameRotation()


Toast.makeText(this@DemoActivity,"LongClick",Toast.LENGTH_LONG).show()
}


override fun onDoubleTapEvent(e: MotionEvent): Boolean {
return true
}


override fun onDown(e: MotionEvent): Boolean {
return true
}
})

分配到你的任何一个视图:

        IPAddress.setOnTouchListener { v, event ->
return@setOnTouchListener  gestureDetector.onTouchEvent(event)
}

这是一个解决方案,如果在执行任何操作之前有第二个循环,则等待

  int init = 0;
myView.setOnClickListener(new View.OnClickListener() {


@Override
public void onClick(View v) {




if (init == 0) {
init++;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {






if (init == 1) {
Log.d("hereGoes", "actionOne");
} else {
Log.d("hereGoes", "actionTwo");
}




init = 0;
}
}, 250);
} else {
init++;
}


}
});

在 Kotlin 这样做的一个简单方法是:

button.setOnTouchListener(object : View.OnTouchListener{
val gestureDetector = GestureDetector(object : GestureDetector.SimpleOnGestureListener(){
override fun onDoubleTap(e: MotionEvent?): Boolean {
//do something here
return super.onDoubleTap(e)
}
})


override fun onTouch(v: View?, event: MotionEvent?): Boolean {
//do something here
gestureDetector.onTouchEvent(event)
return true
}
})

为了检测手势点击的类型,可以实现与此内联的东西 (这里的 projectTextEditText) :

projectText.setOnTouchListener(new View.OnTouchListener() {
private GestureDetector gestureDetector = new GestureDetector(activity, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
projectText.setInputType(InputType.TYPE_CLASS_TEXT);
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
return super.onDoubleTap(e);
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
projectText.setInputType(InputType.TYPE_NULL); // disable soft input
final int itemPosition = getLayoutPosition();
if(!projects.get(itemPosition).getProjectId().equals("-1"))
listener.selectedClick(projects.get(itemPosition));


return super.onSingleTapUp(e);
}
});


@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
return false; //true stops propagation of the event
}
});

我创建了一个简单的库来处理这个问题。它还可以检测到两次以上的点击(这完全取决于你)。导入 ClickCounter 类后,如何使用它来检测单次和多次点击:

ClickCounter counter = new ClickCounter();




view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
counter.addClick();  // submits click to be counted
}
});


counter.setClickCountListener(new ClickCounter.ClickCountListener() {
@Override
public void onClickingCompleted(int clickCount) {
rewardUserWithClicks(clickCount); // Thats All!!😃
}
});

在 Kotlin 你可以试试这个,

就像我在用 cardview 点击,

(例如: 双击我执行喜欢和不喜欢。)

cardviewPostCard.setOnClickListener(object : DoubleClickListener() {
override fun onDoubleClick(v: View?) {


if (holder.toggleButtonLike.isChecked) {
holder.toggleButtonLike.setChecked(false) //
} else {
holder.toggleButtonLike.setChecked(true)


}
}
})

这是 DoubleClickListener 类,

abstract class DoubleClickListener : View.OnClickListener {
var lastClickTime: Long = 0
override fun onClick(v: View?) {
val clickTime = System.currentTimeMillis()
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA) {
onDoubleClick(v)
}
lastClickTime = clickTime
}


abstract fun onDoubleClick(v: View?)


companion object {
private const val DOUBLE_CLICK_TIME_DELTA: Long = 300 //milliseconds
}
}

虽然我喜欢原始答案中方法的简单性

这是我的版本

public abstract class OnDoubleClickListener implements View.OnClickListener {


private static final int TIME_OUT = ViewConfiguration.getDoubleTapTimeout();
private TapHandler tapHandler = new TapHandler();


public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);


@Override
public void onClick(View v) {
tapHandler.cancelSingleTap(v);
if (tapHandler.isDoubleTap()){
onDoubleClick(v);
} else {
tapHandler.performSingleTap(v);
}
}


private class TapHandler implements Runnable {
public boolean isDoubleTap() {
final long tapTime = System.currentTimeMillis();
boolean doubleTap = tapTime - lastTapTime < TIME_OUT;
lastTapTime = tapTime;
return doubleTap;
}
public void performSingleTap(View v) {
view = v;
v.postDelayed(this, TIME_OUT);
}
public void cancelSingleTap(View v) {
view = null;
v.removeCallbacks(this);
}


@Override
public void run() {
if (view != null) {
onSingleClick(view);
}
}
private View view;
private long lastTapTime = 0;
}
}

用法与原文相同

view.setOnClickListener(new OnDoubleClickListener() {


@Override
public void onSingleClick(View v) {


}


@Override
public void onDoubleClick(View v) {


}
});

这是 Kotlin 扩展功能版本:

fun View.setOnDoubleTapListener(action: () -> Unit) {


// instantiate GestureDetectorCompat
val gDetector = GestureDetectorCompat(
this.context,
GestureDetector.SimpleOnGestureListener()
)


// Create anonymous class extend OnTouchListener and SimpleOnGestureListener
val touchListener =
object : View.OnTouchListener, GestureDetector.SimpleOnGestureListener() {
override fun onTouch(view: View?, event: MotionEvent?): Boolean {


gDetector.onTouchEvent(event)
gDetector.setOnDoubleTapListener(this)


return true
}


override fun onDoubleTap(e: MotionEvent?): Boolean {
action()
return true
}
}


this.setOnTouchListener(touchListener)


}

科特林加班

override fun onCreate(savedInstanceState: Bundle?) {
// ...


var listview: ListView = findViewById(R.id.<your_listview_id>)
var itemLastClickTime: Long = 0
var singleClickHandler: Handler = Handler(Looper.getMainLooper())


// ListView item 'double click' and 'single click'
listview.setOnItemClickListener(OnItemClickListener { av, iv, pos, id ->
// if double click occurs, disable single click handler
if (System.currentTimeMillis() - itemLastClickTime < 300) {
singleClickHandler.removeCallbacksAndMessages(null)
// do double click handling
return@OnItemClickListener
}
// store the time of the item's click event
itemLastClickTime = System.currentTimeMillis()
// single click handler only fires, if no double click occured
singleClickHandler.postDelayed({
// do single click handling
}, 300)
})


// ...
}

附加课程

@Override
protected void onCreate(Bundle savedInstanceState) {
// ...


ListView listview = findViewById(R.id.<your_listview_id>);
final long[] itemLastClickTime = {0};
Handler singleClickHandler = new Handler();


listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> av, View iv, int pos, long id) {
// if double click occurs, disable single click handler
if (System.currentTimeMillis() - itemLastClickTime[0] < 300) {
singleClickHandler.removeCallbacksAndMessages(null);
// do double click handling
return;
}
// store the time of the item's click event
itemLastClickTime[0] = System.currentTimeMillis();
// single click handler only fires, if no double click occured
singleClickHandler.postDelayed(new Runnable() {
@Override
public void run() {
// do single click handling
}
}, 300);
}
});


// ...
}