Android:如何检测双击?
Posted
技术标签:
【中文标题】Android:如何检测双击?【英文标题】:Android: How to detect double-tap? 【发布时间】:2011-01-14 03:08:45 【问题描述】:我在执行双击时遇到问题。好吧,我实现了onGestureListener
和gestureDetector
,但我不确定问题出在哪里,这是我的代码:
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
,android 可以检测到它是单击还是双击?
【问题讨论】:
标题问题具有误导性。谁会想要摧毁一个机器人? 【参考方案1】:您可以使用 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;
您可以覆盖侦听器的其他方法以获取单击、弹跳等。
【讨论】:
好的,重新阅读您的帖子后,我想您的问题是,您在 onDown 方法中没有返回 true。手势检测器 onTouch 在你的 onTouch 方法中被调用。 @alan 你能把这个标记为答案吗?这篇文章确实回答了这个问题,并且对未来专门寻找如何实现双击的谷歌用户很有用。长按而不是双击并不总是一种选择。 gestureDetector 被贬低 @Nepster 不,没有被弃用,只有两个构造函数被弃用。 有关更多详细信息和更多示例,请查看这个投票率很高的答案:***.com/a/26529756/4143245【参考方案2】:作为 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)
);
【讨论】:
这不适用于单击。您应该注册一些计时器(例如使用Handler
)以在增量内没有发生第二次点击时执行单击。
它确实适用于单击。执行双击时,您会调用 onSingleClick() 然后调用 onDoubleClick() 这对我的用例来说很好。添加计时器会在 onDoubleClick() 之前删除对 onSingleClick() 的调用,但在我的情况下,在触发事件之前有延迟是不可接受的
我明白了。从逻辑上讲,它们应该是独占的,即要么 onSingleClick() 被调用,要么 onDoubleClick() 被调用,所以你应该等待决定调用哪一个以避免以后的错误。这是 Android 处理长按的方式(参见 View 类中的 onTouchEvent(event) 方法)。此外,您的增量如此之高,200 毫秒更合理。通常在 PC 上,我认为没有人注意到双击延迟。
这个对我有用。我的代码设置为只能使用onTouchListener
,并且我需要检测双击。但是,以它为基础并稍加修改,我就让它工作了。感谢这个好主意!
这是唯一适用于我的解决方案..我尝试了 6-7 种方法,但没有任何效果,但这是 +10 解决方案..【参考方案3】:
你为什么不使用长按?还是您已经将其用于其他用途?长按比双击的优势:
长按是 UI 指南中推荐的交互方式,而不是双击。 这是用户所期望的;用户可能不会找到双击操作,因为他们不会去寻找它 已经是handled in the API。 实现双击会影响对单点触摸的处理,因为您必须等待查看每个单点触摸是否会变成双点触摸,然后才能对其进行处理。【讨论】:
嗯,我正在尝试实现类似海豚浏览器的隐藏和显示选项卡的操作(由于空间限制)......我已经为我的列表视图实现了长按......所以我会需要双击 很公平,我只是想确保您没有忘记长按。 双击监听器的一个很好的例子是视频视图,使其全屏查看。 顺便说一句,长按不再总是优于安卓上的双击;两者都是推荐的手势,取决于常用的用法:google.com/design/spec/patterns/gestures.html# @ToolmakerSteve 我只将双击用作即时缩放操作。长按可以选择项目的地方,启动拖动。 Here is new link Material design 中的手势。【参考方案4】:将“Bughi”“DoubleClickListner”和“Jayant Arora”定时器组合到一个包含的类中:
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)
);
【讨论】:
Handler
is better than TimerTask
。使用handler.postDelayed()
。
如果您使用onSingleTapConfirmed()
,则无需为单击延迟编写所有这些逻辑。见this answer。【参考方案5】:
如果您不想使用自定义视图,则可以使用以下方法。 例如图像视图
// 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.setOnTouchListener(new OnTouchListener()
@Override
public boolean onTouch(View v, MotionEvent event)
// TODO Auto-generated method stub
return gestureDetector.onTouchEvent(event);
);
【讨论】:
【参考方案6】:这是我的解决方案,它使用默认的setOnItemClickListener()
。我有同样的任务要执行。很快我将在我的 github 上发布示例和自定义类。
给出简要说明。我不确定以毫秒为单位的时间是否适合系统(请参阅ViewConfiguration.getDoubleTapTimeout()
来源)在单击和双击之间做出决定。
编辑: 在这里看到它: https://github.com/NikolaDespotoski/DoubleTapListView 或 https://github.com/NikolaDespotoski/DoubleTapListViewHandler
【讨论】:
【参考方案7】:GuestureDetecter 在大多数设备上运行良好,我想知道如何在双击事件中自定义两次单击之间的时间,但我无法做到。我通过“Bughi”“DoubleClickListner”更新了上面的代码,添加了一个使用处理程序的计时器,该处理程序在单击特定延迟后执行代码,如果在该延迟之前执行双击,它将取消计时器和单击任务并且只执行双击任务。 代码运行良好使其非常适合用作双击列表器:
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
);
【讨论】:
干得好,但所有定时器代码确实属于DoubleClickListener类的onClick()方法,以免到处重复【参考方案8】: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();
);
【讨论】:
【参考方案9】:双击和单击
仅双击
使用SimpleOnGestureListener
很容易检测到视图上的双击(如Hannes Niederhausen's answer 所示)。
private class GestureListener extends GestureDetector.SimpleOnGestureListener
@Override
public boolean onDown(MotionEvent e)
return true;
@Override
public boolean onDoubleTap(MotionEvent e)
return true;
我看不出为此重新发明逻辑有多大优势(例如bughi's answer)。
有延迟的双击和单击
您还可以使用SimpleOnGestureListener
将单击和双击区分为互斥事件。为此,您只需覆盖onSingleTapConfirmed
。这将延迟运行单击代码,直到系统确定用户没有双击(即延迟>ViewConfiguration.getDoubleTapTimeout()
)。绝对没有理由为此重新发明所有逻辑(就像在this、this 和其他答案中所做的那样)。
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;
不过,您需要意识到 both onSingleTapUp
和 onDoubleTap
在双击时会被调用。 (这本质上是bughi's answer 所做的以及一些评论者所抱怨的。)您要么需要使用延迟,要么同时调用这两种方法。没有延迟的单击是不可能的,同时知道用户是否要再次点击。
如果您不能接受单击延迟,那么您有几个选择:
接受将调用onSingleTapUp
和onDoubleTap
进行双击。只需适当地划分你的逻辑,这样就没有关系了。这基本上就是我在自定义键盘上实现双击大写锁定时所做的。
不要使用双击。对于大多数事情来说,这不是一个直观的 UI 操作。作为Dave Webb suggests,长按可能更好。您也可以使用 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)
【讨论】:
【参考方案10】:我的解决方案,可能会有所帮助。
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;
【讨论】:
【参考方案11】:即兴 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();
【讨论】:
【参考方案12】:如果您使用的是 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)
【讨论】:
与 Kotlin 配合得很好【参考方案13】:这是在执行任何操作之前等待是否有第二个 clic 的解决方案
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++;
);
【讨论】:
【参考方案14】:实现单双击
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);
【讨论】:
【参考方案15】: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;
【讨论】:
【参考方案16】:线程 + 接口 = DoubleTapListener、AnyTap 监听器等
在这个例子中,我用一个线程实现了 DoubleTap 监听器。 您可以像使用任何 ClickListener 一样将我的侦听器添加到任何 View 对象中。 使用这种方法,您可以轻松地关闭任何类型的点击侦听器。
yourButton.setOnClickListener(new DoubleTapListener(this));
1) 我的监听类
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) 在您的 Activity 中实施
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+"");
相关链接:
你可以看到完整的工作代码HERE
【讨论】:
【参考方案17】:bughi 和 Jayant Arora 的复制粘贴解决方案:
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);
【讨论】:
【参考方案18】:我用来实现相同功能的等效 C# 代码,甚至可以自定义以接受 N 个 Taps
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;
目前,上述代码在引发 View Tapped 事件之前接受 7 作为点击次数。 但它可以定制任何数字
【讨论】:
【参考方案19】:我已经使用kotlin coroutines 实现了一个简单的自定义方法(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
【讨论】:
【参考方案20】:您可以使用GestureDetectorCompat
类实现双击。
在此示例中,当双击 textview 时,您可以执行您的逻辑。
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;
【讨论】:
这是我使用的,它工作正常。不过可以配置吗?一些敏感因素?设置按下之间的时间会触发双击回调?【参考方案21】:我创建了一个简单的库来处理这个问题。它还可以检测到两次以上的点击(这完全取决于您)。导入 ClickCounter class 后,您可以使用它来检测单次和多次点击:
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!!?
);
【讨论】:
【参考方案22】:在 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
【讨论】:
【参考方案23】:虽然我喜欢原始答案中方法的简单性
这是我的版本
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)
);
【讨论】:
【参考方案24】:在 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
)
【讨论】:
【参考方案25】:要检测手势点击的类型,可以实现一些内联的东西
(这里projectText
是EditText
):
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
);
【讨论】:
以上是关于Android:如何检测双击?的主要内容,如果未能解决你的问题,请参考以下文章
Android使用GestureDetector进行手势检测
Android使用GestureDetector进行手势检测